这题是打错题号找到的
题面
题意:给出一个串,用它的子串前后拼接来生成串
问所以长为n的串最少拼接次数的最大值
拼接次数最少就要求每个子串都要是极长的
即它不能和后一个子串的任何前缀形成新的子串
由于子串的某种性质,所以只和首字母有关
即它不能和后一个子串的首字母形成新的子串
在后缀自动机表现为该状态没有对应儿子
由于要拼接次数最大,故每个状态要在关注首字母的情况下取最短
设
f[i][j][k]
f
[
i
]
[
j
]
[
k
]
表示状态i在首字母为j时能接k的最短长度
但这样很蠢,因为状态都是相同的,可以把i去掉
然后得到一个
4∗4
4
∗
4
的矩阵
二分拼接次数mid
对该矩阵做Floyd的倍增
若存在一条长大于等于n的路径
则mid有可能是答案
Kscla有一种厉害的纯图论的想法
在SAM的正向DAG上
若某状态没有某个儿子
则设为初始状态的对应儿子,并附上价值1
就变成求一条长为n的价值最小的路径
把价值为0的边缩掉
就变成一个4个点的完全图
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=200200;
const LL oo=1e18+520;
LL len;
int n;
int son[N][4],dep[N],pre[N],cnt=1,last=1;
LL dp[N][4];
bool vis[N];
char s[N];
struct yy
{
LL f[4][4];
}e,tu,big;
yy operator *(yy x,yy y)
{
yy hy=big;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
for(int k=0;k<4;k++)
hy.f[i][j]=min(hy.f[i][j],x.f[i][k]+y.f[k][j]);
return hy;
}
void Insert(int x)
{
dep[++cnt]=dep[last]+1;
int np=cnt,p=last;
last=cnt;
for(;!son[p][x];p=pre[p])
son[p][x]=np;
if(!p)
pre[np]=1;
else
{
int q=son[p][x];
if(dep[q]==dep[p]+1)
pre[np]=q;
else
{
dep[++cnt]=dep[p]+1;
int nq=cnt;
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
mmcp(son[nq],son[q]);
for(;son[p][x]==q;p=pre[p])
son[p][x]=nq;
}
}
}
void dfs(int x)
{
if(vis[x])
return;
vis[x]=1;
for(int i=0;i<4;i++)
if(son[x][i])
dfs(son[x][i]),dp[x][i]=oo;
for(int i=0;i<4;i++)
{
if(!son[x][i])
dp[x][i]=1;
else
for(int j=0;j<4;j++)
dp[x][j]=min(dp[x][j],dp[son[x][i]][j]+1);
}
}
bool ok(LL b)
{
yy re=e,a=tu;
LL res=oo;
for(;b;b>>=1,a=a*a)
if(b&1)
re=re*a;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
res=min(res,re.f[i][j]);
return res>=len;
}
int main()
{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(i!=j)
e.f[i][j]=oo;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
big.f[i][j]=oo;
cin>>len;
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)
Insert(s[i]-'A');
dfs(1);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
tu.f[i][j]=dp[son[1][i]][j];
LL l=1,r=len+1,ans=len+1;
while(l<=r)
{
LL mid=(l+r)>>1;
if(ok(mid))
ans=min(ans,mid),r=mid-1;
else
l=mid+1;
}
if(ans==len+1)
cout<<0<<endl;
else
cout<<ans<<endl;
return 0;
}