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