「bzoj 4180: 字符串计数」
真是一道好题
首先根据一个非常显然的贪心,如果给出了一个串\(S\),我们如何算最小操作次数呢
非常简单,我们直接把\(S\)拉到\(T\)的\(SAM\)上去跑,如果跑不动了就停下来,重新回到\(1\)继续跑
于是我们建出一个\(SAM\)之后可以写一个这样的暴力,设\(d[i][j][k]\)表示从\(i\)点到\(j\)点走\(i\)条边的最长路,对于那些走不动的边,我们可以接到\(1\)号节点对应的出边上去,边权为\(1\),其余的边权为\(0\),矩阵优化一下就是\(O(|T|^3logn)\)的复杂度
显然\(|T|\)并不允许我们开下如此之大的转移矩阵,尝试换一个角度来考虑这个问题
我们发现我们问题的本质就是最大化最小值,这是不是可以二分一下呢
于是现在的问题变成了对于一个二分出的操作次数\(mid\),判断答案是否能够更大
显然我们如果使用\(mid\)此操作构造出来的串长度小于\(n\),那么我们就可以断定答案可能会更大一些
于是又把问题转化成了利用\(mid\)次操作构造出来的字符串的最小长度
这个如何求呢,我们考虑一次操作无非就是从\(1\)的某一个出边指向的节点到另一个\(1\)的出边指向的节点,所以我们求出这些节点两两之间的最短路就好了
于是我们现在又可以利用矩阵转移了,复杂度\(O(|T|+|c|^3log^2n)\),\(|c|\)为字符集大小
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define inf 922337203685477580
#define maxn 200005
LL n;
char S[maxn>>1];
int m,lst=1,cnt=1,tot;
int len[maxn],fa[maxn],son[maxn][4],q[maxn],vis[maxn],c[maxn];
LL a[4][4],ans[4][4],t[4][4],d[maxn];
inline void ins(int c) {
int p=++cnt,f=lst;lst=p;
len[p]=len[f]+1;
while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
if(!f) {fa[p]=1;return;}
int x=son[f][c];
if(len[f]+1==len[x]) {fa[p]=x;return;}
int y=++cnt;len[y]=len[f]+1;
fa[y]=fa[x],fa[x]=fa[p]=y;
son[y][0]=son[x][0];son[y][1]=son[x][1];
son[y][2]=son[x][2];son[y][3]=son[x][3];
while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
inline void did_t() {
LL mid[4][4];
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++) mid[i][j]=t[i][j],t[i][j]=inf;
for(re int k=0;k<4;k++)
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++)
t[i][j]=min(t[i][j],mid[i][k]+mid[k][j]);
}
inline void did_ans() {
LL mid[4][4];
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++) mid[i][j]=ans[i][j],ans[i][j]=inf;
for(re int k=0;k<4;k++)
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++)
ans[i][j]=min(ans[i][j],mid[i][k]+t[k][j]);
}
inline LL solve(LL now) {
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++) t[i][j]=a[i][j],ans[i][i]=inf;
for(re int i=0;i<4;i++) ans[i][i]=0;
LL b=now;
while(now) {if(now&1ll) did_ans();now>>=1ll;did_t();}
LL tmp=inf;
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++) tmp=min(tmp,ans[i][j]);
return tmp+b;
}
inline int check(LL now) {return solve(now)<=n;}
int main() {
scanf("%lld",&n);scanf("%s",S+1);m=strlen(S+1);
for(re int i=1;i<=m;i++) ins(S[i]-'A');
for(re int i=0;i<4;i++)
for(re int j=0;j<4;j++) a[i][j]=inf;
for(re int i=0;i<4;i++) {
tot=0;q[++tot]=son[1][i];
memset(vis,0,sizeof(vis));
memset(d,20,sizeof(d));d[q[1]]=0;
for(re int j=1;j<=tot;j++) {
int x=q[j];
for(re int k=0;k<4;k++) {
if(vis[son[x][k]]) continue;
if(!son[x][k]) a[i][k]=min(a[i][k],d[x]);
else vis[son[x][k]]=1,d[son[x][k]]=d[x]+1,q[++tot]=son[x][k];
}
}
}
LL l=1,r=n,ans=0;
while(l<=r) {
LL mid=l+r>>1ll;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
if(solve(ans)<n) ans++;
printf("%lld\n",ans);
return 0;
}
「bzoj 4180: 字符串计数」的更多相关文章
- bzoj 4180: 字符串计数
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...
- BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C ...
- BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)
题目链接 先考虑 假设S确定,使构造S操作次数最小的方案应是:对T建SAM,S在SAM上匹配,如果有S的转移就转移,否则操作数++,回到根节点继续匹配S.即每次操作一定是一次极大匹配. 简单证明:假设 ...
- 【BZOJ 4180】 4180: 字符串计数 (SAM+二分+矩阵乘法)
4180: 字符串计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 164 Solved: 75 Description SD有一名神犇叫做Oxe ...
- 【BZOJ-4180】字符串计数 后缀自动机 + 矩阵乘法
4180: 字符串计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 146 Solved: 66[Submit][Status][Discuss] ...
- 「BZOJ 2534」 L - gap字符串
「BZOJ 2534」 L - gap字符串 题目描述 有一种形如 \(uv u\) 形式的字符串,其中 \(u\) 是非空字符串,且 \(v\) 的长度正好为 \(L\), 那么称这个字符串为 \( ...
- 「BZOJ 4502」串
「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...
- 「BZOJ 4228」Tibbar的后花园
「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...
- 「BZOJ 3645」小朋友与二叉树
「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...
随机推荐
- LightningChart 客户案例分享-DCC 环境工程
DCC Dynamics 致力于为建筑管控行业生产OEM的监控和管理产品.公司的旗舰产品“环境物流系统Environmental Logistics System” 用于大型建筑,校园及研究所设施,有 ...
- C#PrintDocument打印尺寸调整
/// <summary> /// 打印的按钮 /// </summary> /// <param name="sender"></par ...
- 使用http维持socket长连接
项目中有遇到问题如下: 1.旧版的cs服务,因为每个用户和唯一的长连接是在登录后绑定的,并且所有的消息报文均是基于该长连接去发送接收的,所以要求node服务要维持一个长连接,然后根据该用户获取长连接, ...
- JDBC的DAO设计模式
在javaEE中,java类的属性通过getter和setter来定义,get(或set)方法去除get(set)后,首字母小写即为Java类的属性.操作java类的属性有一个工具包,BeanUtil ...
- HDU 1874(简单最短路) (大优化)
优先队列那里用greater会报错 http://acm.hdu.edu.cn/showproblem.php?pid=1874 /* 使用pair代替结构 */ #include <iostr ...
- Excel2010条件格式的位置
以下是excel2010的条件格式设置方法(英文版) 具体使用方法可以参考 http://office.microsoft.com/zh-cn/excel-help/HA102809768.aspx
- JS深拷贝继承
所谓深拷贝,就是子对象不紧继承父对象的非引用属性,还能继承父对象的引用属性(Object,Array),当子对象对继承的引用类型属性做修改时,父对象的引用类型不会被修改. 我们先写个浅拷贝的封装函数: ...
- BZOJ 3809Gty的二逼妹子序列 解题报告+data marker
--BZOJ http://www.lydsy.com/JudgeOnline/problem.php?id=3809 考虑对l,r跑莫队,对一组维护美丽度出现次数的桶修改, 然后把桶序列用分块维护查 ...
- drupal7 用到的一些钩子简介
1.hook_user_delete($account) 可用于自定义模块中,当用户被删除时,可以自定义一些自己需要的处理动作 2.hook_mail_alter(&$message) 可用于 ...
- 使用js在HTML中自定义字符串格式化方法
Python中支持字符串格式化,其基本形式如下: str = "I'm {name},{age} years old" print(str.format(name="te ...