zoukankan      html  css  js  c++  java
  • BZOJ2085 [Poi2010]Hamsters

    好题!

    又学习了一下kmp的用途qwq

    我们观察到n非常小

    所以肯定可以通过一些东西来求第i个字符串后面接第j个字符串最少需要接几个字符

    那就是最长的i的后缀和j的前缀相同的长度

    那么我们可以用f[i][j]表示len[j]-x [x表示上面的那个长度]

    然后我们现在就是要求走k步的最小长度和

    有个特殊的算法就是解决这个的就是倍增floyd

    具体倍增floyd的实现 类似于矩阵乘法

    理解一下就是说dis每一次都是扩大一倍【走的路的条数

    然后方便一点的实现就是建一个虚点0 然后向其他所有点连接长度为len[x]的一条边 这样就不需要额外处理了

    //Love and Freedom.
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    #define inf 20021225
    #define N 201
    #define LEN 100010 
    #define LG 30
    using namespace std;
    
    char ch[N][LEN]; int nxt[LEN],len[N]; int n; ll m;
    struct floyd
    {
        ll dis[N][N];
        floyd(){memset(dis,48,sizeof(dis));}
        inline ll* operator[](int i){return dis[i];}
        friend floyd operator*(floyd &x,floyd &y)
        {
            floyd z;
            for(int i=0;i<=n;i++)    for(int j=0;j<=n;j++)
                for(int k=0;k<=n;k++)
                    z[i][j]=min(z[i][j],x[i][k]+y[k][j]);
            return z;
        }
    }f,d,ans;
    int calc(int x,int y)
    {
        int lx=len[x],ly=len[y];
        for(int i=1;i<=lx;i++)    nxt[i]=0;
        for(int i=2;i<=lx;i++)
        {
            nxt[i]=nxt[i-1];
            while(nxt[i] && ch[x][i]!=ch[x][nxt[i]+1])
                nxt[i]=nxt[nxt[i]];
            if(ch[x][i]==ch[x][nxt[i]+1])    nxt[i]++;
        }
        if(x==y)    return lx-nxt[lx];
        int j=0;
        for(int i=1;i<=ly;i++)
        {
            while(j && ch[x][j+1]!=ch[y][i])
                j=nxt[j];
            if(j<lx && ch[x][j+1]==ch[y][i])    j++;
        }
        return lx-j;
    }
    floyd ksm(floyd bs,ll mi)
    {
        floyd ans; for(int i=0;i<=n;i++)    ans[i][i]=0;
        while(mi)
        {
            if(mi&1)    ans=ans*bs;
            bs=bs*bs; mi>>=1;
        }
        return ans;
    }
    int main()
    {
        scanf("%d%lld",&n,&m); f=floyd();
        for(int i=1;i<=n;i++)
            scanf("%s",ch[i]+1),d[0][i]=len[i]=strlen(ch[i]+1);
        for(int i=1;i<=n;i++)    for(int j=1;j<=n;j++)
            d[j][i]=calc(i,j);
        ans=ksm(d,m); ll aans=1ll*inf*inf;
        for(int i=1;i<=n;i++)    aans=min(aans,ans[0][i]);
        printf("%lld
    ",aans);
        return 0;
    }
    View Code
  • 相关阅读:
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    random库的使用
    程序的控制结构
    数据类型
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/11088801.html
Copyright © 2011-2022 走看看