Tandem[CodeChef][後綴數組][分段點]

文章目錄

題目

Vjudge傳送門
連續重複三次字符串稱爲行列字符串,行列字符串的下一個字符和第一個不同稱爲有趣的,否則該行列字符串爲無趣的
問有趣無趣各自個數
在這裏插入圖片描述

思路

根據某論文提出連續重複字符串採用分段點的方式來思考。。。
首先拼接正反串能快速查詢 lcslcslcplcp
然後考慮當前的點 ii+Li,i+L
在這裏插入圖片描述
在這裏插入圖片描述
找到前面開始位置
當然如果超過 L+1L+1 說明之前已經統計過這次答案了
求出 lcplcp 這段重複的總長爲 lcp+llcp+l
形如 3l3l 的一共有 lcp2l+1lcp-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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章