题目
Vjudge传送门
连续重复三次字符串称为行列字符串,行列字符串的下一个字符和第一个不同称为有趣的,否则该行列字符串为无趣的
问有趣无趣各自个数
思路
根据某论文提出连续重复字符串采用分段点的方式来思考。。。
首先拼接正反串能快速查询
和
然后考虑当前的点
找到前面开始位置
当然如果超过
说明之前已经统计过这次答案了
求出
这段重复的总长为
形如
的一共有
个
最后一个是无趣的即可
代码
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
x*=f;
return x;
}
#define MAXN 400000
#define INF 0x3f3f3f3f
char S[MAXN+5];//sa[i]:长度为k的后缀中,排名为i的后缀的位置(不可重)
int b[MAXN+5],sa[MAXN+5],rnk[MAXN+5],tp[MAXN+5],height[MAXN+5];//rnk(可重)
void Bsort(int n,int m){//first: tp[i]=i
for(int i=1;i<=m;i++)
b[i]=0;
for(int i=1;i<=n;i++)
b[rnk[i]]++;
for(int i=1;i<=m;i++)
b[i]+=b[i-1];
for(int i=n;i>=1;i--)
sa[b[rnk[tp[i]]]--]=tp[i];
return ;
}
void GetHeight(char *s,int n){
int k=0;
for(int i=1;i<=n;i++){
if(k) k--;
int j=sa[rnk[i]-1];
while(s[i+k]==s[j+k])
k++;
height[rnk[i]]=k;
}
return ;
}
bool check(int i,int k){return tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+k]==tp[sa[i]+k];}
void SuffixSort(char *s,int n,int m){
for(int i=1;i<=n;i++)
rnk[i]=s[i],tp[i]=i;
Bsort(n,m);
for(int k=1,cnt=0;cnt<n;m=cnt,k<<=1){
cnt=0;
for(int i=n-k+1;i<=n;i++)
tp[++cnt]=i;
for(int i=1;i<=n;i++)
if(sa[i]>k)
tp[++cnt]=sa[i]-k;
Bsort(n,m);
swap(tp,rnk);
cnt=0;
for(int i=1;i<=n;i++)
rnk[sa[i]]=check(i,k)?cnt:++cnt;
}
GetHeight(s,n);
return ;
}
int Log[MAXN+5],f[MAXN+5][20];
void Prepare(int n){
Log[0]=-1;
for(int i=1;i<=n;i++){
if(!(i&(i-1))) Log[i]=Log[i-1]+1;
else Log[i]=Log[i-1];
f[i][0]=height[i];
}
for(int j=1;j<=18;j++)
for(int i=1;i<=n&&(i+(1<<j)-1)<=n;i++)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
inline int RMQ(int L,int R){
int d=Log[R-L+1];
return min(f[L][d],f[R-(1<<d)+1][d]);
}
int main(){
scanf("%s",S+1);
int n=strlen(S+1),m=255;
S[n+1]='#';
for(int i=1;i<=n;i++)
S[n+1+i]=S[n-i+1];
//printf("%s\n",S+1);
SuffixSort(S,2*n+1,m);
Prepare(2*n+1);
LL cnt1=0,cnt2=0;
for(int l=1;l<=n;l++)
for(int i=1;i+l-1<=n;i+=l){
int lcs=RMQ(min(rnk[2*n+2-(i+l-1)],rnk[2*n+2-(i-1)])+1,max(rnk[2*n+2-(i+l-1)],rnk[2*n+2-(i-1)]));
if(lcs>=l)
continue;
//printf("%d\n",lcs);
int x=i-lcs,y=i+l-lcs;
int lcp=RMQ(min(rnk[x],rnk[y])+1,max(rnk[x],rnk[y]));
//printf("%d %d %d\n",x,y,lcp);
if(lcp>=2*l)
cnt1++,cnt2+=lcp-2*l;
}
printf("%lld %lld\n",cnt1,cnt2);
return 0;
}