BZOJ4180:字符串計數(後綴自動機+Floyd+倍增+二分)

這題是打錯題號找到的
題面
題意:給出一個串,用它的子串前後拼接來生成串
問所以長爲n的串最少拼接次數的最大值

拼接次數最少就要求每個子串都要是極長的
即它不能和後一個子串的任何前綴形成新的子串

由於子串的某種性質,所以只和首字母有關
即它不能和後一個子串的首字母形成新的子串
在後綴自動機表現爲該狀態沒有對應兒子

由於要拼接次數最大,故每個狀態要在關注首字母的情況下取最短
f[i][j][k] 表示狀態i在首字母爲j時能接k的最短長度

但這樣很蠢,因爲狀態都是相同的,可以把i去掉

然後得到一個44 的矩陣
二分拼接次數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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章