bzoj-2085 Hamsters
2015-08-31 16:50
351 查看
题意:
给出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<<l步的方案数;
转移显然咯:f[l][i][j]=min(f[l-1][i][k]+f[l-1][k][j]);
这样的话,搞到m-1步的话就是将m-1按位分解的再处理了;
然后加上开头的字符串长度,取最小值;
注意字符串到自己本身是可以的,但是枚举长度时要从len-1开始;
代码:
给出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<<l步的方案数;
转移显然咯:f[l][i][j]=min(f[l-1][i][k]+f[l-1][k][j]);
这样的话,搞到m-1步的话就是将m-1按位分解的再处理了;
然后加上开头的字符串长度,取最小值;
注意字符串到自己本身是可以的,但是枚举长度时要从len-1开始;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 220 #define M 110000 #define seed 131 using namespace std; typedef long long ll; char str [M]; unsigned int hash [M],pow[M]; ll f ,ans[2] ,len ; 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<M;i++) pow[i]=pow[i-1]*seed; for(i=1;i<=n;i++) { scanf("%s",str[i]+1); len[i]=strlen(str[i]+1); for(j=1;j<=len[i];j++) { hash[i][j]=hash[i][j-1]*seed+str[i][j]; } } memset(f,0x3f,sizeof(f)); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { f[0][i][j]=cmp(i,j); } } for(l=1;(1<<l)<=m;l++) { for(k=1;k<=n;k++) { for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { f[l][i][j]=min(f[l][i][j],f[l-1][i][k]+f[l-1][k][j]); } } } } bool flag=0; for(l=0;(1<<l)<=m;l++) { if(1<<l&m) { if(!flag) { flag=1; memcpy(ans[0],f[l],sizeof(ans[0])); continue; } memset(ans[1],0x3f,sizeof(ans[1])); for(k=1;k<=n;k++) { for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { ans[1][i][j]=min(ans[1][i][j],min(ans[0][k][j]+f[l][i][k],ans[0][i][k]+f[l][k][j])); } } } memcpy(ans[0],ans[1],sizeof(ans[0])); } } for(i=1,x=0x3f3f3f3f3f3f3f3fll;i<=n;i++) { for(j=1;j<=n;j++) { x=min(x,len[i]+ans[0][i][j]); } } printf("%lld\n",x); return 0; }
相关文章推荐
- 【Python爬虫学习笔记(3)】Beautiful Soup库相关知识点总结
- 关于在函数中返回动态的内存
- 数据结构与算法分析Java版练习1.15
- 关于ImageLoader 设置圆角参数后不显示图片的问题
- 《深入理解计算机系统》读书笔记3---关于程序运行的思考
- Hadoop 学习笔记
- 1130 -- 矩阵找值
- 剑指offer刷题之c实现的二叉搜索树转换成双向链表
- Unity3D学习笔记《Roll-a-Ball》一
- Hadoop第3周练习--Hadoop2.X编译安装和实验
- 删除字符串中的空格字符
- mac下安装redis
- HTML5 Canvas 绘图――使用 Canvas 绘制图形图文教程 使用html5 canvas 绘制精美的图
- Android与js交互实例
- 在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结。
- 1129 -- 找用户名
- js中一些自带的属性使用
- mac安装memcache
- 单例模式 详解
- 标题:伸展树的基本操作: