bzoj 1398
题意:给出两个字符串,判断这两个串是否循环同构,如果循环同构同时输出字典序最小的表示
最小表示法模板题...
我们可以通过最小表示法做到O(len)
维护两个指针i、j,初始i=0 ,j=1,分别作为起点往下找到第一个不相等的字符 即s[i+k]<>s[j+k]
1、如果 k=len,就找到较小的 即 min(i,j)
1、 s[i+k]>s[j+k],j不变,i=i+k+1(优化:如果i+k+1<=j ,则i=j+1),然后继续往下比较。
2、 s[i+k]<s[j+k],i不变,j=j+k+1(优化:如果j+k+1<=i ,则j=i+1),然后继续往下比较。
直到i或j大于串长,找较小者 即 min(i,j)。
注意:[1]边界:保证i、j、k 均<len
[2]由于比较的时候会超过原串的长度,有两种解决方式:①判断的时候取模 ②在处理之前把字符串复制一遍(但len依旧是原串的长度)
[3]注意数据范围
吐槽:mdzz,这道题写得自己心态崩溃,果然蒟蒻还是回家种地比较好.....
uses math;
var
l,t1,t2 :longint;
i :longint;
ss,s1,s2 :ansistring;
s :array[0..2000010] of char;
function min_p(ss:ansistring):longint;
var
i,j,k:longint;
begin
for i:=0 to 2*l-1 do s[i]:=ss[i+1];
i:=0; j:=1;
while (i<l) and (j<l) do
begin
k:=0;
while (s[i+k]=s[j+k]) and (k<l) do inc(k);
if k=l then break;
if s[i+k]>s[j+k] then
begin
if i+k+1>j then i:=i+k+1 else i:=j+1;
end else
begin
if j+k+1>i then j:=j+k+1 else j:=i+1;
end;
end;
exit(min(i,j));
end;
begin
readln(ss); l:=length(ss);
ss:=ss+ss;
t1:=min_p(ss);
s1:=copy(ss,t1+1,l);
//
readln(ss); l:=length(ss);
ss:=ss+ss;
t2:=min_p(ss);
s2:=copy(ss,t2+1,l);
//
if s1=s2 then
begin
writeln('Yes');
writeln(s1);
end else writeln('No');
end.
bzoj 2882
题意:求最小表示法
只能把最左边放到最右边和直接复制一遍放后面找循环同构有个毛区别....
uses math;
var
n,t1 :longint;
i :longint;
a :array[0..600010] of longint;
function min_p:longint;
var
i,j,k:longint;
begin
i:=0; j:=1;
while (i<n) and (j<n) do
begin
k:=0;
while (a[i+k]=a[j+k]) and (k<n) do inc(k);
if k=n then break;
if a[i+k]>a[j+k] then
begin
if i+k+1>j then i:=i+k+1 else i:=j+1;
end else
begin
if j+k+1>i then j:=j+k+1 else j:=i+1;
end;
end;
exit(min(i,j));
end;
begin
read(n);
for i:=0 to n-1 do read(a[i]);
for i:=0 to n-1 do a[n+i]:=a[i];
t1:=min_p;
for i:=t1 to t1+n-2 do write(a[i],' ');writeln(a[i+1]);
end.
——by Eirlys