链接
题解
我把它上右下左、上右下左…这样循环拨动
然后就发现每次这样“上右下左”弄完一次之后,有数字的格子所占的区域没有发生变化
那么就可以确定,这样一次"上右下左"是一个置换
是置换就可以拆成若干个环
所有环的大小求 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)

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

被折叠的 条评论
为什么被折叠?



