这是一道字符串建模+图论的问题。

题目描述

Byteasar breeds hamsters.

Each hamster has a unique name, consisting of lower case letters of the English alphabet.

The hamsters have a vast and comfortable cage.
Byteasar intends to place a display under the cage to visualize the names of his hamsters.
This display is simply a sequence of letters, each of which can be either lit or not independently.

Only one name will be displayed simultaneously.

The lit letters forming the name have to stand next to each other, i.e., form a contiguous subsequence.

Byteasar wants to be able to display the names of the hamsters on at least $m$ different positions.

However, he allows displaying the same name on multiple different positions, and does not require to be able to display each and every hamster's name.

Note that the occurrences of the names on the display can overlap.

You can assume that no hamster's name occurs (as a contiguous fragment) in any other hamster's name.

Bytesar asks your help in determining the minimum number of letters the display has to have.

In other words, you are to determine the minimum length of a string (consisting of non-capital letters of the English alphabet) that has at least $m$ total occurrences of the hamsters' names (counting multiplicities).

(We say that a string $s$ occurs in the string $t$ if $s$ forms a contiguous fragment of $t$.)

输入输出格式

输入格式:

The first line of the standard input holds two integers $n$ and $m(1\le n\le 200,1\le m\le 10^9)$, separated by a single space, that denote the number of Byteasar's hamsters and the minimum number of occurrences of the hamsters' names on the display.

Each of the following $n$ lines contains a non-empty string of non-capital letters of the English alphabet that is the hamster's name.

The total length of all names does not exceed $100000$ letters.

输出格式:

The first and only line of the standard output should hold a single integer - the minimum number of letters the display has to have.

输入输出样例

输入样例#1:

4 5
monika
tomek
szymon
bernard

输出样例#1:

23

题意:

    给出$n$个字符串$s_i$,这些字符串互不包含。请求出一个最短的字符串$S$,使得这个字符串中出现了$m$次$s$中的字符串。输出$S$的长度。

题解:

    建图是比较容易想到的。不过距离怎么定,$10^9$的长度又怎么控制呢?我们看到字符串的个数只有200,因此考虑floyd。而边有边权,点有点权(1),一个字符串中出现$m$个子串,就要让一条路径经过$m$个点。两个点$(i,j)$之间的边权是$s_i$后面至少添加几个字符能凑出$s_j$。

    因此可以用倍增floyd来做,floyd状态全面,可以表示很多东西。所以用$f[k][i][j]$表示$i$到$j$之间经过$2^k$个点的最短路径。然后做floyd,其中转移只能从$2^{k-1}$处转移。

    而每次内层都是正常的floyd,外层是倍增。此处复杂度是$n^3\log m$。不过匹配字符串需要一定的技巧,这里我用的是字符串hash,虽然复杂度不对,但是可以开-o2啊,还是过了。正解用了AC自动机和KMP来保证复杂度,不过用字符串hash也算学到了一点东西。

    字符串hash就是把字符串用$26/27$进制来表示,字符串的第$i$位要乘上$26^i$或$26^{|s|-i-1}$。在比较两个字符串是否相同时,要把它们的其中一个用乘法变成与另一个同级的。比如abc和bcd,把它们分解就是$1+2\times 26+3\times 26^2$和$2+3\times 26+4 \times 26^2$,我们要比较第一个字符串的bc和第二个字符串的bc是否相等,就要分别取出这两段数字(用前缀和处理即可)。发现取出来是$2\times 26+3\times 26^2$和$2+3\times 26$,可以计算出原来字符串中二者的商值,接着让较小的乘上这个商就可以变到同级了。

Code:

#include<cstdio>
#include<cstring>
long long Min(long long x,long long y)
{
return x<y?x:y;
}
long long f[35][205][205];
char s[205][100010];
int L[205];
long long dis[205],tmp[205];
int Hash[205][100010];
int pow26[100100];
bool Equal(int x,int y,int l)//默认为第一个结尾l个和第二个开头l个
{
return (long long)(Hash[x][L[x]-1]-Hash[x][L[x]-l-1]+19260817)%19260817==(long long)((long long)Hash[y][l-1]*pow26[L[x]-l]%19260817);
}
int main()
{
pow26[0]=1;
for(int i=1;i<=100000;++i)
pow26[i]=pow26[i-1]*26%19260817;
memset(f,0x3f,sizeof(f));
int n,m;
scanf("%d%d",&n,&m);
--m;
for(int i=1;i<=n;++i)
{
scanf("%s",s[i]);
L[i]=strlen(s[i]);
dis[i]=L[i];
for(int j=0;j<L[i];++j)
if(j)
Hash[i][j]=(Hash[i][j-1]+pow26[j]*(s[i][j]-'a'+1))%19260817;
else
Hash[i][j]=s[i][j]-'a'+1;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
int l=Min(L[i],L[j]);
for(int k=(i==j?l-1:l);k;--k)
if(Equal(i,j,k))
{
f[0][i][j]=L[j]-k;
break;
}
if(f[0][i][j]>10000000)
f[0][i][j]=L[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]=0x7ffffffffffffffll;
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];
}
long long ans=0x7ffffffffffffffll;
for(int i=1;i<=n;++i)
ans=ans<dis[i]?ans:dis[i];
printf("%lld\n",ans);
return 0;
}

【字符串】【hash】【倍增】洛谷 P3502 [POI2010]CHO-Hamsters 题解的更多相关文章

  1. 洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速$dp\&Floyd$)

    洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速\(dp\&Floyd\)) 标签:题解 阅读体验:https://zybuluo.com/Junl ...

  2. 洛谷P1783 海滩防御 分析+题解代码

    洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...

  3. 洛谷P4047 [JSOI2010]部落划分题解

    洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...

  4. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  5. [洛谷P3501] [POI2010]ANT-Antisymmetry

    洛谷题目链接:[POI2010]ANT-Antisymmetry 题目描述 Byteasar studies certain strings of zeroes and ones. Let be su ...

  6. 洛谷2375 BZOJ 3670动物园题解

    题目链接 洛谷链接 我们发现题目要我们求的num[i]东西本质上其实是 求有多少以i结尾的非前缀且能与前缀匹配的字符串,而且要求字符串长度小于(i/2) 我们先不考虑字符串长度的限制,看所有以i结尾的 ...

  7. 洛谷10月月赛II题解

    [咻咻咻] (https://www.luogu.org/contestnew/show/11616) 令人窒息的洛谷月赛,即将参加NOIp的我竟然只会一道题(也可以说一道也不会),最终145的我只能 ...

  8. [NOIP提高&洛谷P1024]一元三次方程求解 题解(二分答案)

    [NOIP提高&洛谷P1024]一元三次方程求解 Description 有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d 均为实数),并约 ...

  9. [洛谷P1823]音乐会的等待 题解(单调栈)

    [洛谷P1823]音乐会的等待 Description N个人正在排队进入一个音乐会.人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人.队列中任意两个人A和B,如果他们是相邻或他们之间没 ...

随机推荐

  1. InvocationtargetException 类型转换异常

    日期类型转换不了json格式数据 json转换数据的时候可以设置某个字段不需要转换 jsonconfig=new JsonConfig() //{} 内传入不需要转换的字段 jsonconfig.se ...

  2. CF1073F Choosing Two Paths

    发现从顶点入手不太方便,我们从这个“公共部分最长”开始考虑问题,因为要求这一条公共部分的链最长,可以联想到树的直径,那么本题就是要求一条类似于直径的东西使两个端点除了直径这一条链之外还有不少于两个的儿 ...

  3. Luogu 2597 [ZJOI2012]灾难

    BZOJ 2815. 解法还是挺巧妙的. 放上写得很详细很好懂的题解链接  戳这里. 一个物种$x$如果要灭绝,那么沿着它的入边反向走走走,一定可以走到一个点$y$,如果这个点$y$的物种灭绝了,那么 ...

  4. spark源码阅读之network(2)

    在上节的解读中发现spark的源码中大量使用netty的buffer部分的api,该节将看到netty核心的一些api,比如channel: 在Netty里,Channel是通讯的载体(网络套接字或组 ...

  5. linux学习1----初涉linux

    linux因其稳定高效的特点,受到很多开发者的青睐,因此将其作为服务器的操作系统. 作为一名开发者,程序员,掌握了一定的linux知识和技巧,程序的开发部署和运行也有不小的帮助. linux由于其开源 ...

  6. css总结18:HTML 表单和inut各个常用标签

    1 HTML 表单和输入 1.1 HTML 表单介绍 表单是一个包含表单元素的区域. 表单元素是允许用户在表单中输入内容,比如:文本域(textarea).下拉列表.单选框(radio-buttons ...

  7. C++中的Trivial 、POD、non-POD和Standard Layout概念

    POD types non-POD types Standard Layout types A Formal Definition Informally, a standard layout clas ...

  8. 【转】ANDROID自定义视图——onLayout源码 流程 思路详解

    转载(http://blog.csdn.net/a396901990) 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局 ...

  9. 微软日志工厂 Microsoft.Extensions.Logging 中增加 log4net 的日志输出

    前提: 需要nuget   Microsoft.Extensions.Logging.Log4Net.AspNetCore   2.2.6: 描述:解决 .net core 微软日志工厂 Micros ...

  10. C#中如何向数组中动态添加元素

    转自:https://blog.csdn.net/qq_35938548/article/details/78325558 背景:现需要向数组中循环插入字符串,但C#中的数组是不支持动态添加元素的,只 ...