bzoj-2085 Hamsters

题意:

给出n个长度不大于100000的字符串;

现在要找出一个字符串包括m个这些字符串;

求这个字符串的最小长度;

数据保证字符串不互相包含;

n<=200,m<=1e9;


题解:

数据保证了字符串没有包含的情况。。

那么为了节约考虑,还是要让字符串叠在一起比较合算;

设f[i][j]表示i后面加个j字符串要再加多少字符;

这个怎么求呢?

Hash之后暴力;

RKhash可以O(1)拿出前缀后缀的Hash值,然后枚举长度就暴力出解了;

这里的复杂度看起来很大,但是PoPoQQQ大爷给了我们一些保障= =;

处理出这个之后,这实际上是一张图了;

要求的就是走m-1步的最短路;

然后就要上一个神奇的Floyd算法:倍增Floyd!

状态变成了三维f[l][i][j]表示i到j走1<

转移显然咯:f[l][i][j]=min(f[l-1][i][k]+f[l-1][k][j]);

这样的话,搞到m-1步的话就是将m-1按位分解的再处理了;

然后加上开头的字符串长度,取最小值;

注意字符串到自己本身是可以的,但是枚举长度时要从len-1开始;


代码:

#include
#include
#include
#define N 220
#define M 110000
#define seed 131
using namespace std;
typedef long long ll;
char str[N][M];
unsigned int hash[N][M],pow[M];
ll f[N][N][N],ans[2][N][N],len[N];
ll cmp(int x,int y)
{
	for(ll i=x==y?len[x]-1:min(len[x],len[y]);i>=0;i--)
	{
		if(hash[x][len[x]]-hash[x][len[x]-i]*pow[i]==hash[y][i])
			return len[y]-i;
	}
}
int main()
{
	int n,m,i,j,k,l;
	ll x;
	scanf("%d%d",&n,&m);
	m--;
	pow[0]=1;
	for(i=1;i



你可能感兴趣的:(其他题型,图论,bzoj,OIer刷题记录)