POI2010 题解整理

Description

给定 N(N<=200) N(N个总长度小于 105 10^5的字符串,要求给出一条字符串,其中至少出现 m(m<=109) m(m次上述给定的字符串(必须是其子串)。保证N各字符串两两不互相包含。求最短的字母序列的长度。

Input

  • 第一行n和m,n表示有多少个仓鼠,m表示Tz希望出现名字的次数.。
  • 接下来n行,每行都是仓鼠的名字(中间没有空格)。

Output

  • 输出一行,最短的字母序列的长度。

Sample Input

4 5
monika
tomek
szymon
bernard

Sample Output

23


这回基本是对着po大犇的代码敲起来了,负责任地标成转载。


Solution Solution:

首先对于这种字符串衔接的问题,我们一般预先处理出 f[i][j] f[i][j],表示在 i i后面接上jj需要的代价。但如果直接暴力匹配过来, O(N4) O(N^4)的复杂度就有点吃不消了。所以我们采用Hash优化一维 O(N) O(N)。

在枚举长度的部分似乎并不是 O(N) O(N),然后可能会导致T?由于对于字符串 stri str_i与 strj str_j,如果为了让复杂度尽可能大,则两个字符串必须没有衔接部分,此时一次操作的时间复杂度为 O(min(isize,jsize)) O(min(i_{size},j_{size})),总复杂度可以近似看成

O(∑i=1Nmin(isize,jsize)∗N)≈O(MN)

O(\sum_{i=1}^{N}min(i_{size},j_{size})*N)\approx O(MN)所以复杂度不会导致T的,可以直接上去搞。

但此时又遇到一个问题,发现如果直接对每个字符串都开一个Hash数组,Hash是存不下的,同样如果直接开字符数组,空间复杂度仍然吃不消。显然我们会考虑用string和vector,但是常数问题……(内网神TM开2s)所以学习了Po大犇的指针写法,硬生生卡进了1s。

然后说实在话我就不清楚接下来怎么写了,我写的时候一直在想其他的东西。

构造出上述 f[i][j] f[i][j]很显然我们是要跑类似于最短路一类的算法的,题目中的“m次出现”应该转化成经过m条路。即题目转化为:

  • 给定一张正权值图(所以上述处理 i→i i\to i的情况时不能从最大长度开始枚举),从起点开始要求在图上经过 m m条边,求最短的路径权值总和。

如果跑一般算法就是找到当经过路径数量已经为m后的最小解,复杂度会是类似于O(NMlogN)O(NMlogN)这种的,显然不行。但是,当跑过一些路径到达某个点node时,这个点之后走step步的最短距离与之前的行走是无关的,即满足无后向性。此时我们就可以使用倍增 Floyd Floyd去优化算法了:

  • 定义 f[k][i][j] f[k][i][j]为 i→j i\to j且经过 2k 2^k条路的最短路径值。按照倍增的惯例思想,将m可以拆成不同的 2k 2^k,对于不同的路径权值跑一遍 Floyd Floyd即可。那么此处复杂度为 O(N3logM) O(N^3logM)。

总结一下倍增 Floyd Floyd:

  • 求“经过该图M条边的最值”类型的题可以使用倍增 Floyd Floyd,此时为了Floyd,必须满足这个图满足无后向性,即前面走过的路径不会影响接下来的求值。

又get了一个倍增新用法

#include<bits/stdc++.h>
#define M 202
#define N 200002
#define B 233
#define P 1000000009
#define oo 0x3f3f3f3f3f3f3f3fll
#define inf 0x3f
using namespace std;
int n,m,len[M];
char str[N],*s[M];
int _hash[N],*Hash[M],Base[N];
long long f[M][M],g[M][M],ans[M][M];
int getHash(int *Hash,int L,int R){return (Hash[R]-1LL*Hash[L-1]*Base[R-L+1]%P+P)%P;
}
int calc(int x,int y){for(int i=min(len[x],len[y])-(len[y]<=len[x]);~i;--i)if(getHash(Hash[x],len[x]-i,len[x]-1)==getHash(Hash[y],0,i-1))return i;return 0;
}
int main(){scanf("%d %d",&n,&m);int temp=1,max_len=0;for(int i=1;i<=n;i++){scanf("%s",str+temp);s[i]=str+temp;Hash[i]=_hash+temp;len[i]=strlen(s[i]);//范围[temp,temp+len+1)if(len[i]>max_len)max_len=len[i];temp+=len[i]+1;for(int j=0;j<len[i];j++)Hash[i][j]=(1LL*Hash[i][j-1]*B+s[i][j])%P;//指针访问}Base[0]=1;for(int i=1;i<=max_len;i++)Base[i]=1LL*Base[i-1]*B%P;memset(f,inf,sizeof(f));for(int i=1;i<=n;i++){f[0][i]=len[i];for(int j=1;j<=n;j++)f[i][j]=len[j]-calc(i,j);}memset(ans,inf,sizeof(ans));for(int i=1;i<=n;i++)ans[i][i]=0;if(m&1){memset(g,inf,sizeof(g));for(int k=0;k<=n;k++)for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)if(g[i][j]>f[i][k]+ans[k][j])g[i][j]=f[i][k]+ans[k][j];memcpy(ans,g,sizeof(ans));}for(int step=1;(1<<step)<=m;++step){memset(g,inf,sizeof(g));for(int k=0;k<=n;k++)for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)if(g[i][j]>f[i][k]+f[k][j])g[i][j]=f[i][k]+f[k][j];memcpy(f,g,sizeof(f));//倍增一遍if(m>>step&1){memset(g,inf,sizeof(g));for(int k=0;k<=n;k++)for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)if(g[i][j]>f[i][k]+ans[k][j])g[i][j]=f[i][k]+ans[k][j];memcpy(ans,g,sizeof(ans));}}long long Ans=oo;for(int i=1;i<=n;++i)Ans=min(Ans,ans[0][i]);cout<<Ans<<endl;
}

BZOJ2085 POI2010 Hamsters相关推荐

  1. bzoj2085 [Poi2010]Hamsters 哈希+倍增

    Description Tz养了一群仓鼠,他们都有英文小写的名字,现在Tz想用一个字母序列来表示他们的名字,只要他们的名字是字母序列中的一个子串就算,出现多次可以重复计算.现在Tz想好了要出现多少个名 ...

  2. BZOJ2085: [Poi2010]Hamsters

    题目大意:给出n个互不包含的字符串,要求你求出一个最短的字符串S,使得这n个字符串在S中总共至少出现m次,问S最短是多少 我们构造这样一个矩阵A: A[i][j]表示第j个字符串长度-第i个字符串的最 ...

  3. bzoj2085: [Poi2010]Hamsters(hash+矩阵快速幂)

    传送门 题意:给定n个长度总和不超过1e5的字符串,求一个最短的母串,使所有字符串的出现次数之和=m 这n个字符串保证不互相包含,n≤200 思路: 由于保证字符串两两不相互包含. 因此我们可以考虑 ...

  4. BZOJ2085 : [Poi2010]Hamsters

    设g[i][j]为i串至少加上几个字符后才能包含j,可以通过Hash求出. 然后就是求经过m-1条边的最短路,用倍增加速Floyed即可,时间复杂度$O(n^3\log m)$. #include&l ...

  5. 【bzoj2085】[Poi2010]Hamsters hash+倍增

    dis[i][j][k]表示从第i个串的结尾到第j个串的结尾走过2^k个串的最小长度 dis[i][j][0]=len[j]-cal(i,j) cal(i,j)表示如果i的最长后缀等于j的最长前缀 倍 ...

  6. BZOJ 2085 [POI2010] Hamsters

    题面 Description Tz养了一群仓鼠,他们都有英文小写的名字,现在Tz想用一个字母序列来表示他们的名字,只要他们的名字是字母序列中的一个子串就算,出现多次可以重复计算.现在Tz想好了要出现多 ...

  7. POI2010 Hamsters

    Solution 首先可以Hash搞出每个名字连在另一个名字后面所需要增加的字母数量. 而有些人会担心搞完这个后就超时了,但是如果这个都会超时,这道题目还有什么写的必要?所以大胆去干就好了. 那么下面 ...

  8. BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)

    数组开小毁一生-- 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085 这题在洛谷上有个条件是"互不包含",其实 ...

  9. [Poi2010]Hamsters[字符串hash+floyed+矩阵快速幂]

    tip: 这里题意有两个细节就是:1.出现名字次数[不指定是哪些名字]2.名字是不相互包含的 解题思路:我们先看看样例:szymonikaszymonikatomck;[长度23] 其中:szymon ...

最新文章

  1. 【Java】面向对象编程语法知识点总结
  2. VSCode 小鸡汤 第00期 —— 安装和入门
  3. pb 如何判断缺纸_如何快速判断是否低估?四种相对估值法应用精析
  4. 【数据库系统概论】考研第六部分重点分析【6.1】
  5. 联机分析的列式数据库 clickHouse
  6. 三种嵌入式web服务器(Boa / lighttpd / shttpd)的 linux移植笔记
  7. foreach和volist的区别
  8. Leetcode-MySQL-197. 上升的温度
  9. Maven聚合工程怎么变回普通的Maven工程
  10. [渝粤教育] 云南大学 內部控制理论与实务 参考 资料
  11. 云计算机房防雷规范,弱电机房设计内容规范大全
  12. 腾讯悄悄地发布了Linux版QQ-附安装-卸载方法
  13. 走近CTPN:1. 解读README
  14. 超定方程组和欠定方程组
  15. 北京地区研究生学位英语(GET)词汇
  16. 使用JS监听键盘按下事件(keydown event)
  17. 大哥都是从小弟做起的
  18. 银行账号和身份证号的数据有效性设置
  19. with open (files_name) as f
  20. 时间类型转换为字符串

热门文章

  1. Release和Debug的区别
  2. jsp 配置 oracle数据库连接池,tomcat5/tomcat4中配置数据库(oracle)连接池
  3. 如何利用Visual Studio建立具有MVC框架的网页模型
  4. 午后不犯困的九个绝招
  5. 大唐存储进驻金融信息技术创新生态实验室,助力金融自主生态建设
  6. onvif协议+高性能rtspclient打通大屏投屏协议(一)
  7. StarRocks极客营 | 90天,17名新晋贡献者,SQL Planner 实战回顾
  8. VR、AR、MR、XR
  9. python循环加flag_Python教程:跳出多层循环for、while
  10. 圆圆的球像什么_关于圆圆的月亮像什么的句子有哪些?