[BZOJ2085] [Poi2010]Hamsters

[BZOJ2085] [Poi2010]Hamsters

Description

Tz养了一群仓鼠,他们都有英文小写的名字,现在Tz想用一个字母序列来表示他们的名字,只要他们的名字是字母序列中的一个子串就算,出现多次可以重复计算。现在Tz想好了要出现多少个名字,请你求出最短的字母序列的长度是多少。

Input

输入:第一行n(1<=n<=200)和m(1<=m<=10的9此方),n表示有多少个仓鼠,m表示Tz希望出现名字的次数,接下来n行,每行都是仓鼠的名字(中间没有空格)。

Output

输出:一行,最短的字母序列的长度。

Sample Input

4 5
monika
tomek
szymon
bernard

Sample Output

23

试题分析

显然两个字符串首尾相交需要重合才可以最小,那么我们可以预处理一下两个字符串有顺序连接的代价。
然后我们就可以倍增转移。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
 
using namespace std;
#define LL long long
 
inline LL read(){
    LL x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const LL INF = 1e18;
const LL MAXN = 200010;
const LL Mod = 98152501LL;
const LL base = 131LL;
 
vector<LL> vec[211][2]; string str[211]; LL N,M;
LL Pw[MAXN+1];LL len[211];
inline void Hash(LL x){
    LL las=0; for(LL i=0;i<len[x];i++)
        vec[x][0].push_back(las=(las*base%Mod+(str[x][i]-'a'))%Mod);
    las=0; for(LL i=len[x]-1;i>=0;i--)
        vec[x][1].push_back(las=(las%Mod+(str[x][i]-'a')*Pw[len[x]-i-1])%Mod);
    return ;
} LL to[211][211],f[211][211],g[211][211];
 
 
inline void Solve(LL x){
    if(x==1){
        for(LL i=1;i<=N;i++){
            for(LL j=1;j<=N;j++)
                f[i][j]=to[i][j];
        } return ;
    } Solve(x>>1);
    for(LL i=1;i<=N;i++){
        for(LL j=1;j<=N;j++) g[i][j]=f[i][j];
    } memset(f,0x3f,sizeof(f));
    for(LL i=1;i<=N;i++){
        for(LL j=1;j<=N;j++)
            for(LL k=1;k<=N;k++)
                f[j][k]=min(g[j][i]+g[i][k],f[j][k]);
    } if(x&1){
        for(LL i=1;i<=N;i++){
            for(LL j=1;j<=N;j++) g[i][j]=f[i][j];
        } memset(f,0x3f,sizeof(f));
        for(LL i=1;i<=N;i++){
            for(LL j=1;j<=N;j++){
                for(LL k=1;k<=N;k++)
                    f[j][k]=min(f[j][k],g[j][i]+to[i][k]);
            }
        }
    } return ;
}
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    N=read(),M=read(); Pw[0]=1; for(LL i=1;i<=MAXN;i++) Pw[i]=Pw[i-1]*base%Mod; LL ret=INF;
    for(LL i=1;i<=N;i++) cin>>str[i],len[i]=str[i].length(),Hash(i),ret=min(ret,len[i]);
    if(M==1){printf("%lld\n",ret); return 0;}
    for(LL i=1;i<=N;i++){
        for(LL j=1;j<=N;j++){
            LL fg=0; //to[i][j]=len[i]; if(i==j) continue;
            for(LL k=(i==j?len[i]-2:min(len[i]-1,len[j]-1));k>=0;k--){
                if(vec[i][1][k]==vec[j][0][k]){fg=k+1; break;}
            } to[i][j]=len[j]-fg; 
        }
    } Solve(M-1); 
    LL ans=INF;
    for(LL i=1;i<=N;i++){
        for(LL j=1;j<=N;j++)
            ans=min(ans,len[i]+f[i][j]);
    } printf("%lld\n",ans);
    return 0;
}
posted @ 2018-08-22 09:33  wxjor  阅读(143)  评论(0编辑  收藏  举报