首先,通过预处理计算每个名字的哈希值,然后利用哈希检查名字之间的最长公共前缀,从而确定从一个名字转移到另一个名字的最小代价。
使用倍增动态规划计算转移的最小成本,\(f_{t,i,j}\) 表示从名字 \(i\) 经过 \(2^t\) 步转移到名字 \(j\) 的最小代价,最后通过位运算处理 \(M\) 次转移的组合,最终得到答案。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=210,L=100010,mod=19260817;
char s[N][L];
ll f[35][N][N],dis[N],tmp[N],n,m,ans;
int len[N],hashh[N][L],pow_26[L];
bool check(int x,int y,int l) {
return (ll)(hashh[x][len[x]-1]-hashh[x][len[x]-l-1]+mod)%mod==(ll)((ll)hashh[y][l-1]*pow_26[len[x]-l]%mod);
}
void init() {
pow_26[0]=1;
for(int i=1; i<=100000; i++)
pow_26[i]=pow_26[i-1]*26%mod;
memset(f,0x3f,sizeof(f));
}
int main() {
init();
scanf("%lld%lld",&n,&m);
m--;
for(int i=1; i<=n; i++) {
scanf("%s",s[i]);
len[i]=strlen(s[i]);
dis[i]=len[i];
for(int j=0; j<len[i]; j++)
if(j) hashh[i][j]=(hashh[i][j-1]+pow_26[j]*(s[i][j]-'a'+1))%mod;
else hashh[i][j]=s[i][j]-'a'+1;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
int l=min(len[i],len[j]);
for(int k(i==j?l-1:l); k; --k)
if(check(i,j,k)) {
f[0][i][j]=len[j]-k;
break;
}
if(f[0][i][j]>10000000) f[0][i][j]=len[j];
}
for(int t=1; t<=30; t++)
for(int k=1; k<=n; k++)
for(int j=1; j<=n; j++)
for(int i=1; i<=n; i++)
f[t][i][j]=min(f[t-1][i][k]+f[t-1][k][j],f[t][i][j]);
for(int i=0;i<=30;i++)
if(m&(1<<i)) {
for(int j=1; j<=n; j++) {
tmp[j]=0x3f3f3f3f3f3f3f3fll;
for(int k=1; k<=n; k++)
tmp[j]=tmp[j]<dis[k]+f[i][k][j]?tmp[j]:dis[k]+f[i][k][j];
}
for(int j=1; j<=n; j++)
dis[j]=tmp[j];
}
ans=0x3f3f3f3f3f3f3f3fll;
for(int i=1; i<=n; i++)
ans=min(ans,dis[i]);
printf("%lld\n",ans);
return 0;
}
标签:STC00,int,题解,ll,Hamsters,len,hashh,名字,mod
From: https://www.cnblogs.com/cly312/p/18444922