這題是打錯題號找到的
題面
題意:給出一個串,用它的子串前後拼接來生成串
問所以長爲n的串最少拼接次數的最大值
拼接次數最少就要求每個子串都要是極長的
即它不能和後一個子串的任何前綴形成新的子串
由於子串的某種性質,所以只和首字母有關
即它不能和後一個子串的首字母形成新的子串
在後綴自動機表現爲該狀態沒有對應兒子
由於要拼接次數最大,故每個狀態要在關注首字母的情況下取最短
設 表示狀態i在首字母爲j時能接k的最短長度
但這樣很蠢,因爲狀態都是相同的,可以把i去掉
然後得到一個 的矩陣
二分拼接次數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;
}