Tandem[CodeChef][后缀数组][分段点]

文章目录

题目

Vjudge传送门
连续重复三次字符串称为行列字符串,行列字符串的下一个字符和第一个不同称为有趣的,否则该行列字符串为无趣的
问有趣无趣各自个数
在这里插入图片描述

思路

根据某论文提出连续重复字符串采用分段点的方式来思考。。。
首先拼接正反串能快速查询 l c s lcs l c p lcp
然后考虑当前的点 i i + L i,i+L
在这里插入图片描述
在这里插入图片描述
找到前面开始位置
当然如果超过 L + 1 L+1 说明之前已经统计过这次答案了
求出 l c p lcp 这段重复的总长为 l c p + l lcp+l
形如 3 l 3l 的一共有 l c p 2 l + 1 lcp-2l+1
最后一个是无趣的即可

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_37555704/article/details/106502612