poj3167

时间:2022-01-13 23:42:38

这道题是一道kmp的扩展版的好题
一串匹配一串很容易想到kmp,但是这里的匹配要求的是两个串的名次相同
显然名次是会变的,为了方便,我们可以换一种表达
对于两个等长的串的相同位置,名次相等就是在它之前比它小的数的个数一样,和它相等的数的个数一样
这个我们可以用树状数组维护一下(当然暴力好像也行)
然后匹配就行了

 var ans,a,b,sal,eq:array[..] of longint;
next:array[..] of longint;
c:array[..] of longint;
tot,k,n,m,s,i,j:longint; function lowbit(x:longint):longint;
begin
exit(x and (-x));
end; procedure work(x,p:longint);
begin
while x<=s do
begin
inc(c[x],p);
x:=x+lowbit(x);
end;
end; function ask(x:longint):longint;
begin
ask:=;
while x> do
begin
ask:=ask+c[x];
x:=x-lowbit(x);
end;
end; begin
readln(n,m,s);
for i:= to n do
readln(a[i]);
for i:= to m do //预处理
begin
readln(b[i]);
work(b[i],);
sal[i]:=ask(b[i]-);
eq[i]:=ask(b[i]);
end;
fillchar(c,sizeof(c),);
i:=;
j:=;
next[]:=;
while i<=m do
begin
if (j=) or (ask(b[i]-)=sal[j]) and (ask(b[i])=eq[j]) then
begin
inc(i);
inc(j);
next[i]:=j;
if i>m then break;
work(b[i],);
end
else begin
for k:=i-j+ to i-next[j] do // 保证匹配的串位置一样
work(b[k],-);
j:=next[j];
end;
end;
fillchar(c,sizeof(c),);
i:=;
j:=;
work(a[],);
while (i<=n) do
begin
if (j=) or (ask(a[i]-)=sal[j]) and (ask(a[i])=eq[j]) then
begin
inc(i);
inc(j);
if i<=n then
work(a[i],);
end
else begin
for k:=i-j+ to i-next[j] do
work(a[k],-);
j:=next[j];
end;
if j>m then //注意这里要找出的是所有答案
begin
for k:=i-m to i-next[j] do
work(a[k],-);
inc(tot);
ans[tot]:=i-m;
j:=next[j];
end;
end;
writeln(tot);
for i:= to tot do
writeln(ans[i]);
end.