题目:给出一个矩阵,问是否有一个最小的矩阵是的重复多次该矩阵后可以得到原矩阵(不一定平铺后恰好可以得到整个矩形网格而不多出一部分),求该矩阵的面积。
分析:对于长度为l的一个串s[i],显然l-next[l],l-next[next[l]],…都是能通过复制,完全覆盖字符串的可行串,用get_next得到所有可行的方案。对所有s[i]都可行的最小的划分方案即为最终的宽度w。至于矩阵的高度h,只需要把每个s[i]的前w个字符当作一个正题,记作w[i],对w[1],w[2],…做get_next,得到竖着的最小重复“子串”,即为高h。
下面附程序:
var n,m,i,j,h,w:longint; flag:boolean; v:array[1..10000,1..75] of boolean; next:array[0..10000] of longint; a:array[1..10000,1..75] of char; procedure get1(x:longint); var i,j:longint; begin next[0]:=-1; next[1]:=0; i:=2; j:=0; while i<=m do if (j=-1)or(a[x,i]=a[x,j+1]) then begin inc(j); next[i]:=j; inc(i); end else j:=next[j]; end; procedure get2(x:longint); var i,j:longint; begin next[0]:=-1; next[1]:=0; i:=2; j:=0; while i<=n do if (j=-1)or(a[j+1,x]=a[i,x]) then begin inc(j); next[i]:=j; inc(i); end else j:=next[j]; end; begin readln(n,m); for i:=1 to n do for j:=1 to m do if j<m then read(a[i,j]) else readln(a[i,j]); fillchar(v,sizeof(v),false); for i:=1 to n do begin v[i,m]:=true; get1(i); j:=next[m]; while j>0 do begin v[i,m-j]:=true; j:=next[j]; end; end; for i:=1 to m do begin flag:=true; for j:=1 to n do if not v[j,i] then begin flag:=false; break; end; if flag then begin w:=i; break; end; end; fillchar(v,sizeof(v),false); for i:=1 to w do begin v[n,i]:=true; get2(i); j:=next[n]; while j>0 do begin v[n-j,i]:=true; j:=next[j]; end; end; for i:=1 to n do begin flag:=true; for j:=1 to w do if not v[i,j] then begin flag:=false; break; end; if flag then begin h:=i; break; end; end; writeln(h*w); end.