zoukankan      html  css  js  c++  java
  • 【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


    考虑对每一对仓鼠预处理出接过来最少需要的字符

    发现这个和图上走mm步的最短路径很类似
    矩乘优化即可

    复杂度O(n3logm)O(n^3logm)

    #include<bits/stdc++.h>
    using namespace std;
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define ll long long
    #define pb push_back
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define uint unsigned int
    const int N=205;
    int n,m;
    inline void chemx(ll &a,ll b){
    	a=a>b?a:b;
    }
    inline void chemn(ll &a,ll b){
    	a=a>b?b:a;
    }
    struct mat{
    	ll a[N][N];
    	mat(){memset(a,127/3,sizeof(a));}
    	friend inline mat operator *(const mat &a,const mat &b){
    		mat c=mat();
    		for(int i=1;i<=n;i++)
    		for(int k=1;k<=n;k++)
    		for(int j=1;j<=n;j++)
    		chemn(c.a[i][j],a.a[i][k]+b.a[k][j]);
    		return c;
    	}
    };
    inline mat ksm(mat a,int b,mat res){
    	for(;b;b>>=1,a=a*a)(b&1)&&(res=res*a,1);return res;
    }
    char a[100005];
    uint f[N][100005],p[100005];
    const uint bas=31;
    mat res,now;
    int len[N];
    inline int calc(int a,int b){
    	for(int l=min(len[a],len[b])-1,i=l;i;i--)
    	if(f[a][len[a]]-f[a][len[a]-i]*p[i]==f[b][i])return i;
    	return 0;
    }
    signed main(){
    	n=read(),m=read();
    	p[0]=1;
    	for(int i=1;i<100005;i++)p[i]=p[i-1]*bas;
    	for(int i=1;i<=n;i++){
    		scanf("%s",a+1);
    		len[i]=strlen(a+1);
    		for(int j=1;j<=len[i];j++)
    			f[i][j]=f[i][j-1]*bas+a[j];
    	}
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)res.a[i][j]=len[j]-calc(i,j),now.a[i][j]=0;
    	if(m>1)now=ksm(res,m-2,res);ll ans=1e18;
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)chemn(ans,len[i]+now.a[i][j]);
    	cout<<ans;
    }
    
  • 相关阅读:
    优秀开源项目
    详细解读Android中的搜索框(四)—— Searchable配置文件
    详细解读Android中的搜索框(三)—— SearchView
    详细解读Android中的搜索框(二)—— Search Dialog
    判断listview滑动方向的代码片段
    详细解读Android中的搜索框(一)—— 简单小例子
    通过Spannable对象设置textview的样式
    用开源项目circular progress button实现有进度条的Button
    低版本系统兼容的ActionBar(七)自定义Actionbar标题栏字体
    WebView入门
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328801.html
Copyright © 2011-2022 走看看