妮可妮可妮

【问题描述】
小 P 特别喜欢动画 Love Live 中的角色妮可,每当他听到妮可说“niconiconi”
时,他总会感到特别兴奋,还会露出绅士般的微笑。
作为一名理论计算机科学家,小 P 开始研究“niconiconi”这种串的特点。
他发现,“niconiconi”可以拆成“ni”、“co”、“ni”、“co”、“ni”这
五部分。
对这个模型进行了抽象后,小 P 发现,任何形如 ABABA 的串都有类似的特点,
其中 A、B 为非空串,我们称这样的串满足性质 P。比如“aaaaa”就满足性质 P,
而“ababab”却不满足性质 P。
有了这个革命性的发现,结合他最近新学的数据结构“后缀树”,小 P 决定
造一道题。这道题是这样的,小 P 给你一个仅由小写英文字母组成的串 S,你拿
到这个串之后,小 P 会问你 q 个问题,每个问题形如“S 的后缀 p 是不是满足性
质 P 的串呀”。
注:设 S 的长度为 n,那么 S[1..n]的后缀 p 就是子串 S[p..n]。


【输入】
输入文件名:nico.in
第一行一个仅由小写英文字母组成的串 S。
第二行一个整数 q。
接下来 q 行,每行一个数 p_i,表示第 i 次的问题是:“S 的后缀 p_i 是不
是满足性质 P 的串呀”。

【输出】
输出文件名:nico.out
输出文件一共 q 行,第 i 行为对第 i 个问题的回答。
如果满足性质 P,回答:“niconiconi”。(不包含引号)
如果不满足性质 P,回答:“no”。(不包含引号)


【数据范围】
测试点 1..3:|S|≤100
测试点 1..6:|S|≤1000
测 试 点
1..10 : 1 ≤ |S| ≤ 5*10 5 , 1 ≤ q ≤ 10 5

形如ABABA的串,可以化为(端点)A(断点2)[BA(2)](断点1)[BA(1)]

我们令f[i]为1~i与1~n 的最长公共后缀

枚举断点1为i

[BA(1)]=str[i~n]

[BA(2)]=str[j~i-1]   (n-i+1=i-j)

则端点的范围为j-min(g[j-1],n-i)

则j-min(g[j-1],n-i)~~j-1的后缀显然都符合ABABA

那么有几个问题:

1.怎麽求出f[i],用二分,二分长度并匹配,匹配失败则缩小长度

2.怎麽快速判断字符串相同,用字符串hash

3.j-min(g[j-1],n-i)~~j-1用差分数组全部+1,就可以O(1)查询

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long lol;
 7 lol p=31,Mod=1000000007,ha[500005],pw[500005];
 8 char s[500001];
 9 int f[500005],ans[500005],len;
10 lol hash(int l,int r)
11 {
12   return (ha[r]-(ha[l-1]*pw[r-l+1])%Mod+Mod)%Mod;
13 }
14 int main()
15 {int i,j,x;
16   scanf("%s",s+1);
17   len=strlen(s+1);
18   pw[1]=p;
19   pw[0]=1;
20   ha[1]=s[1]-'a';
21   for (i=2;i<=len;i++)
22     ha[i]=(ha[i-1]*p+(s[i]-'a'))%Mod,pw[i]=(pw[i-1]*p)%Mod;
23   for (i=1;i<=len;i++)
24     {int l,r,as;
25       l=0;r=i;as=0;
26       while (l<=r)
27     {
28       int mid=(l+r)/2;
29       if (hash(i-mid+1,i)==hash(len-mid+1,len)) as=mid,l=mid+1;
30       else r=mid-1;
31     }
32       f[i]=as;
33     }
34   for (i=len-1;i>=1;i--)
35     {
36       int l=len-i+1,j=i-l;
37       if (j>1)
38       if (f[i-1]>=l)
39     {
40       int ll=j-min(f[j-1],l-1);
41       ans[ll]++;ans[j]--; 
42     }
43     }
44   for (i=1;i<=len;i++)
45     {
46       ans[i]+=ans[i-1];
47     }
48   int q;
49   cin>>q;
50   while (q--)
51     {
52       scanf("%d",&x);
53       if (ans[x]) printf("niconiconi
");
54       else printf("no
");
55     }
56 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7561751.html