题解:SP15553 STC00 - Hamsters

首先,通过预处理计算每个名字的哈希值,然后利用哈希检查名字之间的最长公共前缀,从而确定从一个名字转移到另一个名字的最小代价。

使用倍增动态规划计算转移的最小成本,\(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;
}
posted @ 2024-10-02 17:45  cly312  阅读(28)  评论(0)    收藏  举报