妮可妮可妮
【问题描述】
小 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\n"); 54 else printf("no\n"); 55 } 56 }