BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)
先考虑 假设S确定,使构造S操作次数最小的方案应是:对T建SAM,S在SAM上匹配,如果有S的转移就转移,否则操作数++,回到根节点继续匹配S。即每次操作一定是一次极大匹配。
简单证明:假设S="ABCD",T有子串"A","AB","CD","BCD",那么步数最小方案是选"AB"再接上"CD",而不是提前断开选择"A"+"BCD",因为后者只会使后面的子串变长,"CD"有可能继续接子串而"BCD"却不能。
那么对于本题,我们要使操作次数多,拼接的子串尽量短,应是选择最短的到达一个不能匹配某字符的位置,即!son[x][c]。那么下次便是从根沿\(son[root][c]\)再挑一个结束字符沿最短路径走。
而且字符集大小只有4。令\(f[i][j]\)表示从根节点沿字符\(i\)出边出发,到达某个没有字符\(j\)转移的节点的最短路径。
那么两次操作形成的S长度为\(l[i][k]=f[i][j]+f[j][k]\),于是考虑二分操作次数\(m\),求\(m\)次操作后可以得到的\(S\)最短的长度是否\(\leq n\)。可以用矩阵快速幂/倍增Floyd加速转移。
\(f\)可以在SAM上求。令\(g[x][c]\)表示在\(x\)节点到达一个没有\(c\)转移的节点的最短距离,则\(g[x][c]=\min\{g[son[x]][c]+1\}\)。
最后\(f[i][j]=g[son[1][i]][j]+1\)。
不是枚举子节点更新\(fa[x]\) 而是枚举\(son[x]\)更新\(x\)啊mdzz。
操作次数会达到longlong。
另外可以直接转化为图上问题:https://blog.csdn.net/kscla/article/details/79504779
即设可转移边边权为0,不能转移的连回根节点对应转移点,边权为1。那么就是从根节点出发,走n步,求最大价值。还是缩下没用的边然后二分+倍增Floyd。
INF要设为2e18不是1e18,否则minlen==n时直接ans=mid,break不对。。(大概是数据问题就这里不对)
被INF卡还行。
//10296kb 384ms
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=2e5+7;
const LL INF=2e18;//!...
struct Suffix_Automaton
{
int tot,las,fa[N],son[N][4],len[N],A[N],tm[N],g[N][4],f[4][4];
LL n;//,g[N][4],f[4][4];
char s[N>>1];
struct Matrix
{
LL a[4][4];
Matrix operator *(const Matrix &x)const
{
Matrix res;
for(int i=0; i<4; ++i)
for(int j=0; j<4; ++j)
{
LL tmp=INF;
for(int k=0; k<4; ++k)
tmp = std::min(tmp, a[i][k]+x.a[k][j]);
res.a[i][j]=tmp;
}
return res;
}
}Base;
Matrix FP(Matrix x,LL k)
{
Matrix t=x;
for(--k; k; k>>=1, x=x*x)
if(k&1) t=t*x;
return t;
}
void Insert(int c)
{
int p=las,np=++tot; len[las=np]=len[p]+1;
for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=son[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot; len[nq]=len[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
fa[nq]=fa[q], fa[q]=fa[np]=nq;
for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
}
}
}
void Build()
{
las=tot=1;
scanf("%lld%s",&n,s+1); int l=strlen(s+1);
for(int i=1; i<=l; ++i) Insert(s[i]-'A');
for(int i=1; i<=tot; ++i) ++tm[len[i]];
for(int i=1; i<=l; ++i) tm[i]+=tm[i-1];
for(int i=1; i<=tot; ++i) A[tm[len[i]]--]=i;
memset(g,0x3f,sizeof g);
for(int i=1; i<=tot; ++i)
for(int j=0; j<4; ++j)
if(!son[i][j]) g[i][j]=0;
for(int i=tot,x=A[i]; i; x=A[--i])
for(int j=0,s; j<4; ++j)
if(s=son[x][j])
for(int k=0; k<2; ++k)
g[x][k]=std::min(g[x][k],g[s][k]+1),
g[x][k+2]=std::min(g[x][k+2],g[s][k+2]+1);//闲的...但还没都展开...
for(int i=0; i<4; ++i)
for(int j=0; j<4; ++j)
Base.a[i][j]=g[son[1][i]][j]+1;
}
int Check(LL x)
{
Matrix res = FP(Base,x);
int s=0;
for(int i=0; i<4; ++i)
for(int j=0; j<4; ++j)
if(res.a[i][j]==n) s=1;
else if(res.a[i][j]<n) return 2;
return s;//最短长度=n已经最优了 <n则x次一定不够
}
void Solve()
{
LL l=1,r=n,mid,ans=1,s;
while(l<=r)
{
if((s=Check(mid=l+r>>1))==1) {ans=mid; break;}//ans=mid, r=mid-1;
else if(!s) r=mid-1;
else ans=l=mid+1;
}
printf("%lld\n",ans);
}
}sam;
int main()
{
sam.Build(), sam.Solve();
return 0;
}
BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)的更多相关文章
- BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C ...
- 【BZOJ 4180】 4180: 字符串计数 (SAM+二分+矩阵乘法)
4180: 字符串计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 164 Solved: 75 Description SD有一名神犇叫做Oxe ...
- 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂
[题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
- Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂)
Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂) 题目链接 题解: 多串匹配问题,很容易想到是AC自动机 先构建忌讳词语的AC自动机,构建时顺便记录一下这个点以及它的所有后 ...
- 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)
[BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...
- 【BZOJ-4180】字符串计数 后缀自动机 + 矩阵乘法
4180: 字符串计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 146 Solved: 66[Submit][Status][Discuss] ...
- bzoj 4180: 字符串计数
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...
- BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)
考虑对一个串如何分割能取得最大值.那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串.于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根. 然后考虑dp.设f[i][j]表示前i ...
随机推荐
- 一些常见修改命令(针对ubuntu 14.04 持续更新中...)
1.PS1 在哪: echo $PS1 vi /etc/bash.bashrc /W输出最后一个目录 /w输出完整目录 2.设置静态IP地址:vim /etc/network/i ...
- SQL语句(十三)多表查询
多表查询 1. 笛卡尔乘积 简单格式 SELECT * 或字段列表 FROM 数据表列表 实例 --1. 笛卡尔乘积 (五条件的连接--很多条件无意义) Select * from Student, ...
- python 玩具代码
脚本语言的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python是告诉操作系统执行这个脚本的时候,调用/usr/bin下的python ...
- 【整理】HTML5游戏开发学习笔记(5)- 猜谜游戏
距上次学习笔记已有一个多月过去了,期间由于新项目赶进度,以致该学习计划给打断,十分惭愧.书本中的第六章的例子相对比较简单.所以很快就完成. 1.预备知识html5中video标签的熟悉 2.实现思路对 ...
- CSS-3 文字阴影—text-shadow 的使用
text-shadow还没有出现的时候,大家在网页中的阴影就是用ps一张图片作为背景.那么现在有了CSS3的这个属性,日后我们的工作会更简洁些. text-shadow之前出现过,不过不久就被Pass ...
- HTML5 移动开发(CSS3设计移动页面样式)
1.如何创建CSS样式表 2.CSS3的卓越特性 3.基于设备属性改变样式的媒体查询 4.如何使用属性改变元标签创建更美观移动页面 层叠样式表是移动WEB开发中的一个重要组成部分,本次分享将学到如 ...
- SDWebImage源码阅读-第二篇
一 SDWebImageManager的downloadImageWithURL的方法 上一篇,我们刚开了个头,分析了一下开始加载图片之前如何取消其他正在下载的任务,接着,我们回到 - (void) ...
- json 删除、添加对象
1. 定义json对象 var entryJson = []; 2. 删除.添加对象 entryJson.pop(); //删除最后一个对象 entryJson.push({ //往 ...
- A - Jugs ZOJ - 1005 (模拟)
题目链接:https://cn.vjudge.net/contest/281037#problem/A 题目大意:给你a,b,n.a代表第一个杯子的容量,b代表第二个杯子的容量,然后一共有6种操作.让 ...
- [Alg::Trick]小白鼠找毒酒
题目来源:牛客网 https://www.nowcoder.com/questionTerminal/c26c4e43c77440ee9497b20118871bf1 8瓶酒一瓶有毒,用人测试.每次测 ...