[NWPU2019]组队排位赛 H - Tile Game

本文探讨了通过上右下左循环操作解决特定问题的方法,分析了如何将这些操作视为置换,并将其分解为多个环来求解最小公倍数,从而得出算法的最终解答。

链接

点击看题

题解

我把它上右下左、上右下左…这样循环拨动

然后就发现每次这样“上右下左”弄完一次之后,有数字的格子所占的区域没有发生变化

那么就可以确定,这样一次"上右下左"是一个置换

是置换就可以拆成若干个环

所有环的大小求 l c m lcm lcm就是答案

代码

T = int(input())
for kase in range(T):
    r, c = [int(x) for x in input().split()]
    m=[]
    
    for i in range(r):
        s = input()
        m.append(s)
    
    a = [ [0 for i in range(c)] for i in range(r) ]
    tot = 0
    for i in range(r):
        for j in range(c):
            if m[i][j]=='#':
                tot += 1
                a[i][j] = tot
    o = []
    for i in range(r):
        o.append(a[i].copy())
 
    # up
    for j in range(c):
        cnt = 0
        for i in range(r):
            if a[i][j]>0:
                cnt += 1
        for i in range(cnt):
            a[i][j] = a[r-cnt+i][j]
        for i in range(cnt,r):
            a[i][j] = 0
    
    # right
    for i in range(r):
        cnt = 0
        for j in range(c):
            if a[i][j]>0:
                cnt+=1
        for j in range(cnt):
            a[i][c-j-1] = a[i][cnt-j-1]
        for j in range(c-cnt):
            a[i][j]=0
    
    # down
    for j in range(c):
        cnt = 0
        for i in range(r):
            if a[i][j]>0:
                cnt += 1
        for i in range(cnt):
            a[r-i-1][j] = a[cnt-i-1][j]
        for i in range(r-cnt):
            a[i][j] = 0
    
    # left
    for i in range(r):
        cnt = 0
        for j in range(c):
            if a[i][j]>0:
                cnt+=1
        for j in range(cnt):
            a[i][j] = a[i][c-cnt+j]
        for j in range(cnt,c):
            a[i][j]=0
    
    to = [0 for i in range(tot+10)]
 
    for i in range(r):
        for j in range(c):
            if a[i][j]>0:
                to[a[i][j]] = o[i][j]
    
    def gcd(a, b):
        if b==0:
            return a
        return gcd(b,a%b)
    
    def lcm(a, b):
        return a*b//gcd(a,b)
 
    vis = [False for i in range(tot+10)]
 
    def run(pos):
        s = 0
        while vis[pos] == False:
            vis[pos] = True
            s += 1
            pos = to[pos]
        return s
    
    ans = 1
    for i in range(1,tot+1):
        if vis[i] == False:
            cir_size = 0
            t = run(i)
            ans = lcm(ans,t)
    
    print('Case '+str(kase+1)+':',ans%78294349)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值