BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)
数组开小毁一生……
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085
这题在洛谷上有个条件是“互不包含”,其实bzoj的数据也满足这个条件,否则我目前已知的所有做法都是错的。
个人觉得AC自动机可以用其他办法做,但是没试过
KMP(或者hash), \(f[i][j]\)表示\(i\)完了接上\(j\)需要多少个字符,直接用KMP求出最长的同时是\(j\)串的前缀和\(i\)串的后缀的串即可
然后求走\((m-1)\)步的最短路,倍增Floyd
并不是多串匹配一定要用AC自动机!即使不考虑正确性,AC自动机的Trie树在复杂度上可能还多个字符集大小,不一定比KMP快,一定要合理选择!
代码
KMP:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
using namespace std;
const int N = 200;
const int S = 26;
const int L = 1e5+1e3;
const int LGM = 30;
const llong INF = 1e17;
llong f[N+3][N+3],g[N+3][N+3],g0[N+3][N+3];
char a[L+3];
int nxt[L+3];
int len[L+3];
int slen[L+3];
int n; llong m;
void update(llong &x,llong y) {x = min(x,y);}
int KMP(char str1[],char str2[],int len1,int len2)
{
for(int i=0; i<=len1; i++) nxt[i] = 0;
for(int i=2; i<=len1; i++)
{
nxt[i] = nxt[i-1];
while(nxt[i]!=0 && str1[i]!=str1[nxt[i]+1])
{
nxt[i] = nxt[nxt[i]];
}
if(str1[i]==str1[nxt[i]+1]) nxt[i]++;
}
if(str1==str2)
{
return len1-nxt[len1];
}
else
{
int j = 0;
for(int i=1; i<=len2; i++)
{
while(j && str1[j+1]!=str2[i])
{
j = nxt[j];
}
if(j<len1 && str1[j+1]==str2[i]) j++;
}
return len1-j;
}
}
int main()
{
scanf("%d%lld",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%s",a+slen[i-1]+1); len[i] = strlen(a+slen[i-1]+1); slen[i] = slen[i-1]+len[i]+1; a[slen[i]] = ' ';
}
for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
for(int i=1; i<=n; i++) f[i][i] = len[i];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
g0[j][i] = KMP(a+slen[i-1],a+slen[j-1],len[i],len[j]);
}
}
/*
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("g0: %d %d %lld\n",i,j,g0[i][j]);
}
}
*/
m--;
while(m>0)
{
if(m&1)
{
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
update(g[i][j],f[i][k]+g0[k][j]);
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
f[i][j] = g[i][j];
g[i][j] = INF;
}
}
}
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
update(g[i][j],g0[i][k]+g0[k][j]);
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
g0[i][j] = g[i][j];
g[i][j] = INF;
}
}
m>>=1;
}
llong ans = INF;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
ans = min(ans,f[i][j]);
}
}
printf("%lld\n",ans);
return 0;
}
AC自动机WA+TLE代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#define llong long long
using namespace std;
const int N = 200;
const int S = 26;
const int L = 1e5+1;
const int LGM = 30;
const llong INF = 1e17;
void update(llong &x,llong y) {x = min(x,y);}
llong g0[N+3][N+3],g[N+3][N+3],f[N+3][N+3];
int len[N+3];
int fail[L+3];
int son[L+3][S+3];
int idpos[N+3];
char a[L+3];
int id[L+3];
int que[L+3];
int dep[L+3];
int n,rtn,siz; llong m;
void insertstr(char str[],int sid)
{
int u = rtn;
for(int i=1; i<=len[sid]; i++)
{
if(son[u][str[i]])
{
u = son[u][str[i]];
}
else
{
siz++; son[u][str[i]] = siz;
u = siz;
}
}
id[u] = sid;
idpos[sid] = u;
}
void add(int u,int v,llong w)
{
update(g0[id[u]][id[v]],w);
}
void getfail()
{
int head = 1,tail = 0;
for(int i=1; i<=S; i++)
{
int v = son[rtn][i];
if(v)
{
tail++; que[tail] = v;
fail[v] = rtn;
}
}
while(head<=tail)
{
int u = que[head]; head++;
for(int i=1; i<=S; i++)
{
int v = son[u][i];
if(v) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = v;}
else {son[u][i] = son[fail[u]][i];}
}
}
}
void bfs(int s)
{
printf("bfs(%d)\n",s);
for(int i=1; i<=siz; i++) dep[i] = 0;
int head = 1,tail = 1; que[1] = s;
while(head<=tail)
{
int u = que[head]; head++;
int v = fail[i];
for(int i=1; i<=S; i++)
{
v = son[u][i];
if(v && dep[v]==0)
{
dep[v] = dep[u]+1;
add(s,v,dep[v]);
tail++; que[tail] = v;
}
}
}
}
int main()
{
scanf("%d%lld",&n,&m); rtn = siz = 0;
for(int i=1; i<=n; i++)
{
scanf("%s",a+1); len[i] = strlen(a+1);
for(int j=1; j<=len[i]; j++) a[j] -= 96;
insertstr(a,i);
}
getfail();
for(int i=0; i<=siz; i++) printf("AC%d fail%d\n",i,fail[i]);
for(int i=0; i<=siz; i++) {for(int j=1; j<=S; j++) {if(son[i][j]) {printf("son[%d][%c]=%d\n",i,j+96,son[i][j]);}}}
for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
for(int i=1; i<=n; i++) f[i][i] = 0ll;
for(int i=1; i<=siz; i++)
{
if(id[i])
{
bfs(i);
}
}
/*
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("g0: %d %d %lld\n",i,j,g0[i][j]);
}
}
*/
m--;
while(m>0)
{
if(m&1)
{
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
update(g[i][j],f[i][k]+g0[k][j]);
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
f[i][j] = g[i][j];
g[i][j] = INF;
}
}
}
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
update(g[i][j],g0[i][k]+g0[k][j]);
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
g0[i][j] = g[i][j];
g[i][j] = INF;
}
}
m>>=1;
}
llong ans = INF;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
ans = min(ans,len[i]+f[i][j]);
}
}
printf("%lld\n",ans);
return 0;
}
/*
4 11
aaaaaaa
aaaa
aaaaaa
aaaaaaaaaa
*/
BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)的更多相关文章
- 洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速$dp\&Floyd$)
洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速\(dp\&Floyd\)) 标签:题解 阅读体验:https://zybuluo.com/Junl ...
- [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)
[BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表) 题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段 ...
- BZOJ 3052/Luogu P4074 [wc2013]糖果公园 (树上带修莫队)
题面 中文题面,难得解释了 BZOJ传送门 Luogu传送门 分析 树上带修莫队板子题... 开始没给分块大小赋初值T了好一会... CODE #include <bits/stdc++.h&g ...
- BZOJ 3931 / Luogu P3171 [CQOI2015]网络吞吐量 (最大流板题)
题面 中文题目,不解释: BZOJ传送门 Luogu传送门 分析 这题建图是显然的,拆点后iii和i′i'i′连容量为吞吐量的边,根据题目要求,111和nnn的吞吐量看作∞\infty∞. 然后用di ...
- BZOJ 3894 / Luogu P4313 文理分科 (拆点最小割)
题面 中文题面- BZOJ 传送门 Luogu 传送门 分析 这道题类似于BZOJ 3774 最优选择,然后这里有一篇博客写的很好- Today_Blue_Rainbow's Blog 应该看懂了吧- ...
- BZOJ 2039 / Luogu P1791 [2009国家集训队]employ人员雇佣 (最小割)
题面 BZOJ传送门 Luogu传送门 分析 考虑如何最小割建图,因为这仍然是二元关系,我们可以通过解方程来确定怎么建图,具体参考论文 <<浅析一类最小割问题 湖南师大附中 彭天翼> ...
- BZOJ 2127 / Luogu P1646 [国家集训队]happiness (最小割)
题面 BZOJ传送门 Luogu传送门 分析 这道题又出现了二元关系,于是我们只需要解方程确定怎么连边就行了 假设跟SSS分在一块是选文科,跟TTT分在一块是选理科,先加上所有的收益,再来考虑如何让需 ...
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
随机推荐
- 从头认识Spring-2.7 自己主动检測Bean(1)-@Component @Repository @Service @Controller
这一章节我们来讨论一下自己主动检測Bean. 1.domain 厨师类: package com.raylee.my_new_spring.my_new_spring.ch02.topic_1_19; ...
- 查找存在某字符的文件列表,不包括svn文件
find . ! -wholename '*.svn*' -print | xargs grep "img" | awk -F ':.' '{print $1}' | uniq
- 使用Genymotion无法连接网络设置代理
A.) Genymotion 的 Proxy 设置 , 在Android的设置 -> 无线网络 -> Wi-Fi 之中 1.) 在 设置 -> 无线网络 -> Wi-Fi 里面 ...
- WCF学习笔记——配置服务引用
WCF传过来的东西要序列化. 比如,在WCF服务中,象这么个方法 public IEnumerable<UserItem> GetUserList() 默认情况下,在客户端会调用,是这样: ...
- 2498 IncDec Sequence
2498 IncDec Sequence 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 给 ...
- 快速搭建ELK集中化日志管理平台
由于我们的项目是分布式,服务分布于多个服务器上,每次查看日志都要登录不同服务器查看,而且查看起来还比较麻烦,老大让搭一个集中化日志管理的东西,然后就在网上找到了这个东西ELK ELK就是elastic ...
- 使用ZeppelinHub来存储和展示ZeppelinNoteBook
0.序 说实在的这个功能太赞了 在一开始接触的时候不知道有这个功能,我尝试做一下配置,发现非常的棒. 棒的原因有两点: 可以在随时随地有互联网的地方访问自己的ZeppelinHub来查看Zeppeli ...
- Objective-C—— @Property详解
实例变量:属性其实说直白点就是 ivar + setter + getter(实例变量+存取方法),不过在OC中属性多了字面量这一系列特殊关键字使得OC属性有些不同. 成员属性我们应该都使用过,比如现 ...
- href标签中target的几个属性值
没有指定<a>的target属性值时,默认是"_blank,可以参考以下代码的设置来控制<a href="#" target="_blank& ...
- 从Hive1.0升级到Hive2.0(删除hive1.x中的元数据, 并不是数据迁移)
软件环境: linux系统: CentOS6.7 Hadoop版本: 2.6.5 zookeeper版本: 3.4.8 主机配置: 一共m1, m2, m3这五部机, 每部主机的用户名都为centos ...