题目链接

先考虑 假设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;
}

转载于:https://www.cnblogs.com/SovietPower/p/9249426.html

BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)相关推荐

  1. BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  2. 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂

    [题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...

  3. 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂

    [题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...

  4. bzoj 4002: [JLOI2015]有意义的字符串(特征根法+矩阵快速幂)

    4002: [JLOI2015]有意义的字符串 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 960  Solved: 415 [Submit][S ...

  5. BZOJ 2004 公交线路(状压DP+矩阵快速幂)

    注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...

  6. [BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)

    文章目录 title solution code title solution 针对数据编程才是坠吊的!!! 观察数据,发现分隔数据的 L L L跨度过大,没有衔接--推测很有可能是分数据做法 ①:考 ...

  7. BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

    状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...

  8. [BZOJ]4180: 字符串计数 SAM+矩阵乘法+二分

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  9. BZOJ 3277 串 BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)...

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

最新文章

  1. Hyper-V之02 虚拟机复制与故障转移
  2. 深度学习之pytorch(一) 环境安装
  3. python 结构数组_Python数组
  4. Kernel Memory Layout on ARM Linux
  5. 基于php的工厂管理系统,PHP设计模式——工厂模式
  6. 深度学习笔记(21) 边缘检测
  7. 【Kafka】Exiting due to: org/apache/kafka/common/protocol/SecurityProtocol
  8. 长兴哪里有免费学计算机,2020年曲靖长兴职业技术学校计算机应用专业介绍
  9. VS编译时自动引用Debug|Release版本的dll
  10. android 一位小数_android如何保留小数点后x位数字
  11. MultiDesk远程桌面连接
  12. 大数据技术与人工智能的关系
  13. java 反射 field.set,java 反射之Field
  14. Java基础——使用json所要用到的jar包下载
  15. win10下 phantomjs下载安装与使用
  16. 1 初识Mybatis
  17. mt6739耳机通道配置外置功放
  18. 基于远程服务器的共享文件实现
  19. angular.min.js:80 Error: [$injector:unpr] http://errors.angularjs.org/1.2.9/
  20. mysql5.7无损复制_MySQL5.7新特性:lossless replication 无损复制

热门文章

  1. c程序隐藏linux,linux 下隐藏进程的一种方法
  2. 浮点与定点的二进制存储
  3. C++ 程序内存泄漏检测方法
  4. python 利用pandas库实现 读写 .csv文件
  5. tensorflow 之 ValuError: At least two variables have the same name: bottom/bn1/beta_power0 等
  6. initrd.img相关
  7. C++Primer:字面值常量类调用函数错误(p268书中示例报错)
  8. tar.gz 文件类型(tar文件的解压和压缩)
  9. linux磁盘分区fdisk命令详解
  10. 随机变量X与随机变量函数Y=g(X)的概率分布