zoukankan      html  css  js  c++  java
  • 【BZOJ2085】[Poi2010]Hamsters hash+倍增floyd

    【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

    题解:先求出任意两个串之间的最长前缀后缀,然后DP。用f[i][j]表示出现了i次,最后一个名字是j的最短长度。用倍增floyd优化即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    typedef long long ll;
    const ll m1=9997957;
    const ll m2=1000000007;
    const int maxn=100010;
    int n,m,tot;
    int lp[210],rp[210],bel[maxn];
    int head[10000000],next[maxn];
    ll val[maxn],mn;
    char str[maxn];
    struct matrix
    {
    	ll a[210][210];
    	matrix (){memset(a,0x3f,sizeof(a));}
    	ll* operator [] (int b){return a[b];}
    	matrix operator * (matrix b)
    	{
    		int i,j,k;
    		matrix c;
    		for(k=1;k<=n;k++)	for(i=1;i<=n;i++)	for(j=1;j<=n;j++)	c[i][j]=min(c[i][j],a[i][k]+b[k][j]);
    		return c;
    	}
    }tr,ans;
    void add(int a,int b,ll c)
    {
    	val[b]=c,next[b]=head[a],head[a]=b;
    }
    void find(int b,int a,ll c)
    {
    	for(int i=head[a];i;i=next[i])
    		if(rp[bel[b]]-b==i-lp[bel[i]]+1&&c==val[i]&&!(bel[b]==bel[i]&&b==lp[bel[b]]&&i==rp[bel[i]]-1))
    			tr[bel[b]][bel[i]]=min(tr[bel[b]][bel[i]],(ll)rp[bel[i]]-i-1);
    }
    void pm(int y)
    {
    	while(y)
    	{
    		if(y&1)	ans=ans*tr;
    		tr=tr*tr,y>>=1;
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i,j;
    	ll h1,h2,b1,b2;
    	for(i=1;i<=n;i++)
    	{
    		lp[i]=rp[i-1],scanf("%s",str+lp[i]),rp[i]=strlen(str);
    		for(h1=h2=0,j=lp[i];j<rp[i];j++)	bel[j]=i,h1=(h1*233+str[j])%m1,h2=(h2*233+str[j])%m2,add(h1,j,h2);
    	}
    	for(i=1;i<=n;i++)	for(j=1;j<=n;j++)	tr[i][j]=rp[j]-lp[j];
    	for(i=1;i<=n;i++)
    	{
    		for(h1=h2=0,b1=b2=1,j=rp[i]-1;j>=lp[i];j--)
    		{
    			h1=(h1+b1*str[j])%m1,h2=(h2+b2*str[j])%m2,b1=b1*233%m1,b2=b2*233%m2;
    			find(j,h1,h2);
    		}
    	}
    	for(i=1;i<=n;i++)	ans[i][i]=rp[i]-lp[i];
    	pm(m-1);
    	for(mn=1ll<<60,i=1;i<=n;i++)	for(j=1;j<=n;j++)	mn=min(mn,ans[i][j]);
    	printf("%lld",mn);
    	return 0;
    }
  • 相关阅读:
    ASP.NET 4.0的ClientIDMode属性
    关于sql链接超时的问题
    Image.Url 无法使用 Server.MapPath(使用后无论如何也不显示)
    C# 中字符串转换成日期
    Linux RAID 磁盘管理
    脚本编写
    挂载一个NFS共享
    配置NFS服务
    配置多用户SMB挂载
    通过 SMB 共享目录
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7366935.html
Copyright © 2011-2022 走看看