CF30E Tricky and Clever Password

XI.CF30E Tricky and Clever Password

一开始看错题,硬生生把难度上升了很多……

所以以下的解法是按照我看错的题意进行的,即 \(S=T_1+S_1+T_2+S_2+T_3+S_3+T_4\),其中 \(S_2\) 是奇回文串,\(S_1\)\(S_3\) 相反,除 \(S_2\) 外一切都可为空。

我们发现,最优情形下,\(S_2\) 一定是极长回文串,因为这样严格不劣于非极长回文串的情形。

于是我们考虑枚举所有极长回文串(共 \(n\) 个),问题转换为求原串的前缀和后缀的最长公共相反串。考虑对后缀反转,就变成了两个串(即原串以及原串的反串)各自前缀的最长公共子串。

考虑把两个串放一块跑广义SAM。在每个节点,记录它所对应的 \(\text{endpos}\) 集合中,来自原串的最左端的串和来自反串的最右端的串。考虑对于一个 \(S_2\),只有某些 \(\text{endpos}\) 集合是合法的,当且仅当其上述最左串和最右串全都与 \(S_2\) 无交。假如我们把它看作二维的坐标的话,我们发现问题转换为二维数点问题。直接上BIT维护即可。

但是这是看错题的解法。正确的题意中,要求 \(T_4=\varnothing\)。这没有关系,只需保留所有最右串恰好是后缀的集合即可。

时间复杂度 \(O(n\log n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
struct Suffix_Automaton{
	int ch[26],mn,mx,len,fa;
	Suffix_Automaton(){mn=0x3f3f3f3f,mx=-1;}
}t[400100];
int cnt=1;
int Add(int x,int c){
	if(t[x].ch[c]){
		int y=t[x].ch[c];
		if(t[y].len==t[x].len+1)return y;//(x,c) has been added into the tree already.
		int yy=++cnt;t[yy]=t[y];
		t[yy].len=t[x].len+1,t[y].fa=yy;
		for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
		return yy;
	}
	int xx=++cnt;t[xx].len=t[x].len+1;
	for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
	if(!x){t[xx].fa=1;return xx;}
	int y=t[x].ch[c];
	if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
	int yy=++cnt;t[yy]=t[y];
	t[yy].len=t[x].len+1;
	t[y].fa=t[xx].fa=yy;
	for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
	return xx;
}
vector<int>v[400100];
char s[100100];
int S;
void chmn(int &x,int y){if(y<x)x=y;}
void chmx(int &x,int y){if(y>x)x=y;}
void dfs(int x){for(auto y:v[x])dfs(y),chmn(t[x].mn,t[y].mn),chmx(t[x].mx,t[y].mx);}
struct dat{
	int x,y,z;
	dat(){x=y=z=0;}
	dat(int X,int Y,int Z){x=X,y=Y,z=Z;}
	friend bool operator<(const dat&p,const dat&q){return p.z<q.z;}
}bit[100100];
bool cmp(dat&p,dat&q){return p.x<q.x;}
void ADD(int x,dat d){
	x++;
	while(x)bit[x]=max(bit[x],d),x-=x&-x;
}
dat SUM(int x){
	x++;
	dat ret;
	while(x<=S)ret=max(ret,bit[x]),x+=x&-x;
	return ret;
}
vector<dat>p,q;
int rad[100100];
void Manacher(){
	int Rpos=-1,Centre=-1;
	for(int i=0;i<S;i++){
		if(i<Rpos)rad[i]=min(Rpos-i,rad[2*Centre-i]);
		while(i-rad[i]>=0&&i+rad[i]<S&&s[i-rad[i]]==s[i+rad[i]])rad[i]++;
		if(i+rad[i]>Rpos)Rpos=i+rad[i],Centre=i;
		q.push_back(dat(i-rad[i],i+rad[i],rad[i]*2-1));
	}
}
vector<int>rs;
int mx;
int main(){
	scanf("%s",s),S=strlen(s);
	for(int i=0,las=1;i<S;i++)chmn(t[las=Add(las,s[i]-'a')].mn,i);
	for(int i=S-1,las=1;i>=0;i--)chmx(t[las=Add(las,s[i]-'a')].mx,i);
	for(int i=2;i<=cnt;i++)v[t[i].fa].push_back(i);
	dfs(1);
	for(int i=1;i<=cnt;i++)if(t[i].mn<t[i].mx&&(t[i].mx+t[i].len==S))p.push_back(dat(t[i].mn,t[i].mx,t[i].len));
	Manacher();
	sort(p.begin(),p.end(),cmp),sort(q.begin(),q.end(),cmp);
	for(int i=0,j=0;i<q.size();i++){
		while(j<p.size()&&p[j].x<=q[i].x)ADD(p[j].y,p[j]),j++;
		if(mx<q[i].z)mx=q[i].z,rs={q[i].x+1,q[i].y-1};
		dat tmp=SUM(q[i].y);
		if(mx<q[i].z+2*tmp.z)mx=q[i].z+2*tmp.z,rs={tmp.x-tmp.z+1,tmp.x,q[i].x+1,q[i].y-1,tmp.y,tmp.y+tmp.z-1};
	}
	printf("%d\n",rs.size()/2);
	for(int i=0;i<rs.size();i+=2)printf("%d %d\n",rs[i]+1,rs[i+1]-rs[i]+1);
	return 0;
} 

posted @ 2021-04-01 12:08  Troverld  阅读(59)  评论(0编辑  收藏  举报