【NOI2014】动物园___变形KMP

题目大意:

KMP算法中,对于字符串 S 的前 i 个字符构成的子串,既是它的后缀又是它的前缀的字符串中(它本身除外),最长的长度记作 next[i]。
而现在希望求出一个更强大 num 数组——对于字符串 S 的前 i 个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,这种字符串的数量记作num[i]。例如 S 为 aaaaa,则 num[4] = 2。这是因为 S 的前 4 个字符为 aaaa,其中a 和 aa 都满足性质‘既是后缀又是前缀’,同时保证这个后缀与这个前缀不重叠。
而 aaa 虽然满足性质‘既是后缀又是前缀’,但遗憾的是这个后缀与这个前缀重叠了,所以不能计算在内。同理,num[1] = 0,num[2] = num[3] = 1,num[5] = 2。 ”
企鹅向参观动物园的你寻求帮助,给出了你N个询问,你能否帮助企鹅写一个程序分别求出 num 数组呢?
特别地,为了避免大量的输出,你不需要输出 num[i] 分别是多少,你只需要输出∏ (num[i] + 1) 对 1,000,000,007 取模的结果即可。
其中∏ (num[i] + 1)= (num[1] + 1) × (num[2] + 1) × ⋯ × (num[L] + 1)。

对于数据点而言:
1 n ≤ 5, L ≤ 50
2 n ≤ 5, L ≤ 200
3 n ≤ 5, L ≤ 200
4 n ≤ 5, L ≤ 10,000
5 n ≤ 5, L ≤ 10,000
6 n ≤ 5, L ≤ 100,000
7 n ≤ 5, L ≤ 200,000
8 n ≤ 5, L ≤ 500,000
9 n ≤ 5, L ≤ 1,000,000
10 n ≤ 5, L ≤ 1,000,000

题解:

这题其实是比较容易就就能想到思路的,
我们可以设num[i]表示前i个字符前缀跟后缀相同(不包括本身)的情况有多少种,
例如,对于一个字符串
abaaba
num[6]=2
因为前6个字符中,前缀a和后缀a相同,前缀aba和后缀aba相同,所以有2种
这一步可以在对字符串S做KMP的过程中计算。
然后我们每次对于一个Si用next[i]去跳到一个j的位置使得2*j≤i,这时候s[1..j]跟s[i-j+1,i]相同且它们并没有重叠的部分,这时候我们发现num[j]对于i而言同样成立,所以答案累加上num[j]

时间复杂度:O(NL)

代码:

const
         modn=1000000007;
var
         rp,next:array [0..1000001] of longint;
         i,j,k,l,n,op:longint;
         s:ansistring;
         ans:int64;

begin
         readln(n);
         for k:=1 to n do
            begin
                  readln(s);
                  next[1]:=0;
                  rp[1]:=1;
                  j:=0;
                  for i:=2 to length(s) do
                     begin
                           while (j>0) and (s[j+1]<>s[i]) do j:=next[j];
                           if s[j+1]=s[i] then inc(j);
                           next[i]:=j;
                           rp[i]:=rp[j]+1;
                     end;
                  j:=0;
                  ans:=1;
                  for i:=2 to length(s) do
                     begin
                           while (j>0) and (s[j+1]<>s[i]) do j:=next[j];
                           if s[j+1]=s[i] then inc(j);
                           while 2*j>i do j:=next[j];
                           ans:=(ans*(rp[j]+1)) mod modn;
                     end;
                  writeln(ans);
            end;
end.

你可能感兴趣的:(pascal,规律与思维,KMP)