【bzoj2085】[Poi2010]Hamsters hash+倍增

来源:互联网 发布:知画的真名 编辑:程序博客网 时间:2024/05/29 19:19

dis[i][j][k]表示从第i个串的结尾到第j个串的结尾走过2^k个串的最小长度

dis[i][j][0]=len[j]-cal(i,j)
cal(i,j)表示如果i的最长后缀等于j的最长前缀

倍增floyd好了。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#define inf 100000000000000000ll#define maxn 210using namespace std;unsigned long long p1=233,p2=10007;unsigned long long hash1[210][10010],hash2[210][10010],P1[10100],P2[10010];long long f[40][maxn][maxn],g[maxn][maxn],g1[maxn][maxn];char s[maxn][10100];int len[maxn];long long ans;int m,n;unsigned long long Hash1(int x,int l,int r){return hash1[x][r]-hash1[x][l-1]*P1[r-l+1];}unsigned long long Hash2(int x,int l,int r){return hash2[x][r]-hash2[x][l-1]*P2[r-l+1];}int cal(int x,int y){for (int i=min(len[x],len[y])-1;i>=0;i--)  if (Hash1(x,len[x]-i+1,len[x])==Hash1(y,1,i) && Hash2(x,len[x]-i+1,len[x])==Hash2(y,1,i)) return i;}int Log(int x){int ans=0;while (x) x>>=1,ans++;return ans;}int main(){//freopen("username.in","r",stdin);//freopen("username.out","w",stdout);scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) scanf("%s",s[i]+1);P1[0]=1;P2[0]=1;for (int i=1;i<=1000;i++) P1[i]=P1[i-1]*p1,P2[i]=P2[i-1]*p2;for (int i=1;i<=n;i++){len[i]=strlen(s[i]+1);hash1[i][0]=0;hash2[i][0]=0;for (int j=1;j<=len[i];j++) hash1[i][j]=hash1[i][j-1]*p1+s[i][j]-'a',hash2[i][j]=hash2[i][j-1]*p2+s[i][j]-'a';}int cnt=Log(m);for (int k=0;k<=cnt;k++)  for (int i=0;i<=n;i++)    for (int j=0;j<=n;j++)      f[k][i][j]=inf;for (int i=1;i<=n;i++) f[0][0][i]=len[i],f[0][i][0]=inf;for (int i=1;i<=n;i++)  for (int j=1;j<=n;j++)    f[0][i][j]=len[j]-cal(i,j);for (int k=1;k<=cnt;k++)  for (int p=0;p<=n;p++)    for (int i=0;i<=n;i++)      if (f[k-1][i][p]!=inf)        for (int j=0;j<=n;j++)          if (f[k-1][p][j]!=inf)            f[k][i][j]=min(f[k][i][j],f[k-1][i][p]+f[k-1][p][j]);bool flag=0;for (int k=0;k<=cnt;k++)  if (m&(1<<k))  {  if (flag)  {  for (int i=0;i<=n;i++)    for (int j=0;j<=n;j++)      g1[i][j]=inf;  for (int p=0;p<=n;p++)    for (int i=0;i<=n;i++)      if (g[i][p]!=inf)        for (int j=0;j<=n;j++)          if (f[k][p][j]!=inf)            g1[i][j]=min(g1[i][j],g[i][p]+f[k][p][j]);  for (int i=0;i<=n;i++)    for (int j=0;j<=n;j++)      g[i][j]=g1[i][j];  }  else  {  for (int i=0;i<=n;i++)    for (int j=0;j<=n;j++)      g[i][j]=f[k][i][j];  flag=1;  }  }long long ans=inf;for (int i=1;i<=n;i++) ans=min(ans,g[0][i]);printf("%lld\n",ans);return 0;}


0 0
原创粉丝点击