标签:str span tps code pre force printf test 前缀
给定一个字符串,找出其所有相同的前缀和后缀,每行打印两个数字a,b,表示前缀(后缀)的长度,以及它在字符串中出现的次数。
前置知识:统计每个前缀在原字符串中出现的次数。
考虑位置\(i\)的前缀函数值\(nxt[i]\)。根据定义,其意味着字符串\(s\)一个长度为\(nxt[i]\)的前缀在位置\(i\)出现并以\(i\) 为右端点,同时不存在一个更长的前缀满足前述定义。与此同时,更短的前缀可能以该位置为右端点。容易看出,我们遇到了在计算前缀函数时已经回答过的问题:给定一个长度为\(j\)的前缀,同时其也是一个右端点位于\(i\)的后缀,下一个更小的前缀长度\(k< j\)是多少?该长度的前缀需同时也是一个右端点为\(i\)的后缀。因此以位置\(i\)为右端点,有长度为\(nxt[i]\)的前缀,有长度为\(nxt[nxt[i]-1]\)的前缀,有长度为\(nxt[nxt[nxt[i]-1]-1]\)的前缀,等等,直到长度变为0。故而我们可以通过下述方式计算答案。
vector<int> ans(n + 1);
for (int i = 0; i < n; i++) ans[nxt[i]]++;
for (int i = n - 1; i > 0; i--) ans[nxt[i - 1]] += ans[i];
for (int i = 0; i <= n; i++) ans[i]++;
(参见OI-wiki)
预处理出每个前缀出现的次数,字符串所有相等的前缀和后缀可以通过不断地nxt获得。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int N=1e5+10;
char a[N];
int nxt[N],cnt[N];
struct node{
int pos,num;
}ans[N];
int tot;
int la;
void getnxt(char *p){
nxt[0]=0;
for(int i=1;i<la;i++){
int j=nxt[i-1];
while(j>0&&p[i]!=p[j]) j=nxt[j-1];
if(p[i]==p[j]) j++;
nxt[i]=j;
}
}
void solve(){
for(int i=0;i<la;i++) cnt[nxt[i]]++;
for(int i=la-1;i>=0;i--) cnt[nxt[i-1]]+=cnt[i];
for(int i=0;i<=la;i++) cnt[i]++;
}
bool cmp(node a,node b){
return a.pos<b.pos;
}
int main(){
scanf("%s",a);
la=strlen(a);
getnxt(a);
solve();
int now=la;
while(now){
ans[++tot].pos=now;
ans[tot].num=cnt[now];
now=nxt[now-1];
}
sort(ans+1,ans+1+tot,cmp);
printf("%d\n",tot);
for(int i=1;i<=tot;i++){
printf("%d %d\n",ans[i].pos,ans[i].num);
}
return 0;
}
Codeforces 432D-Prefixes and Suffixes
标签:str span tps code pre force printf test 前缀
原文地址:https://www.cnblogs.com/qjy73/p/12492525.html