用户工具

站点工具


2020-2021:teams:legal_string:jxm2001:字符串_1

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:jxm2001:字符串_1 [2020/08/27 10:51]
jxm2001
2020-2021:teams:legal_string:jxm2001:字符串_1 [2020/08/27 11:38] (当前版本)
jxm2001
行 369: 行 369:
 接下来从大到小枚举每个与前缀相同的后缀,初始为 $f(n)$,然后不断迭代 $f$ 即可。如果该后缀长度小于 $\text{pre}$,则得到答案。时间复杂度 $O(|S|)$。 接下来从大到小枚举每个与前缀相同的后缀,初始为 $f(n)$,然后不断迭代 $f$ 即可。如果该后缀长度小于 $\text{pre}$,则得到答案。时间复杂度 $O(|S|)$。
  
 +=== 习题二 ===
 +
 +[[https://​www.luogu.com.cn/​problem/​CF432D|CF432D]]
 +
 +== 题意 ==
 +
 +给你一个长度为 $n$ 的字符串。定义“完美子串”既是它的前缀也是它的后缀,求“完美子串”的个数且统计这些子串的在字符串中出现的次数。
 +
 +== 题解 1 ==
 +
 +考虑求出每个位置的 $z$ 函数,统计每个前缀出现次数。关于 $z$ 函数统计前缀次数,如果 $s[l,​r]=s[1,​r-l+1]$,显然有 $s[l,​r-1]=s[1,​r-l]$。
 +
 +于是可以直接用桶维护 $z$ 函数,然后求后缀和。
 +
 +然后从大到小枚举每个与前缀相同的后缀并记录答案,判定条件为 $i+z(i)-1=n$。时间复杂度 $O(|S|)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=1e5+5;
 +namespace KMP{
 + int z[MAXN];
 + void get_z(char *s,int n){
 + z[1]=n;
 + _rep(i,​2,​n)z[i]=0;​
 + for(int i=2,​l=0,​r=0;​i<​=n;​i++){
 + if(i<​=r)z[i]=min(z[i-l+1],​r-i+1);​
 + while(i+z[i]<​=n&&​s[z[i]+1]==s[i+z[i]])z[i]++;​
 + if(i+z[i]-1>​r)l=i,​r=i+z[i]-1;​
 + }
 + }
 +}
 +int c[MAXN];
 +char s[MAXN];
 +int main()
 +{
 + gets(s+1);
 + int n=strlen(s+1);​
 + KMP::​get_z(s,​n);​
 + stack<​int>​ s;
 + _rep(i,​1,​n){
 + if(i+KMP::​z[i]-1==n)
 + s.push(KMP::​z[i]);​
 + c[KMP::​z[i]]++;​
 + }
 + for(int i=n;​i;​i--)c[i-1]+=c[i];​
 + enter(s.size());​
 + while(!s.empty()){
 + printf("​%d %d\n",​s.top(),​c[s.top()]);​
 + s.pop();
 + }
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
 +
 +== 题解 2 ==
 +
 +考虑求出每个位置的 $f$ 函数,统计每个前缀出现次数。
 +
 +然后从大到小枚举每个与前缀相同的后缀并记录答案,初始为 $n$,然后不断迭代 $f$ 即可。时间复杂度 $O(|S|)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=1e5+5;
 +namespace KMP{
 + int f[MAXN];
 + void get_f(char *s,int n){ 
 + int pos=0;
 + f[1]=0;
 + _rep(i,​2,​n){
 + while(pos&&​s[i]!=s[pos+1])pos=f[pos];​
 + if(s[i]==s[pos+1])pos++;​
 + f[i]=pos;​
 + }
 + }
 +}
 +char s[MAXN];
 +int c[MAXN];
 +int main()
 +{
 + gets(s+1);
 + int n=strlen(s+1);​
 + KMP::​get_f(s,​n);​
 + _rep(i,​1,​n)c[KMP::​f[i]]++;​
 + stack<​pair<​int,​int>​ >pt;
 + for(int i=n;​i;​i--)c[KMP::​f[i]]+=c[i];​
 + for(int i=n;​i;​i=KMP::​f[i])
 + pt.push(make_pair(i,​c[i]+1));​
 + enter(pt.size());​
 + while(!pt.empty()){
 + printf("​%d %d\n",​pt.top().first,​pt.top().second);​
 + pt.pop();
 + }
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
2020-2021/teams/legal_string/jxm2001/字符串_1.1598496676.txt.gz · 最后更改: 2020/08/27 10:51 由 jxm2001