「BZOJ 4502」串
「BZOJ 4502」串
题目描述
兔子们在玩字符串的游戏。首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合 \(S\) 中某个字符串的前缀。比如对于字符串集合 \(\{ "abc","bca" \}\),字符串 \("abb"\),\("abab"\)是“好”的 \(("abb"="ab"+"b", abab="ab"+"ab")\) ,而字符串 \(“bc”\)不是“好”的。
兔子们想知道,一共有多少不同的“好”的字符串。
\(1 \leq N \leq 10000, 1 \leq |S| \leq 30\)
解题思路 :
观察发现,对于同一个串可能会有多种划分方式形成两个前缀拼接的形式,直接大力计算不方便处理重复的情况
此时不妨统计每一种答案串中最具有“特征”的那一种划分方式,在所有划分方式中,最小化第二个串的长度
也就是说,如果第一个串已经确定,第二个串的前缀与第一个串的公共部分全部划给第一个串
问题的一部分转化为一个 \(Trie\) 树上求 \(Borders\) 的问题,也就是 \(AC\) 自动机的 \(fail\) 指针,所以可以把问题规约到 \(AC\) 自动机上面
此时答案的形态有两种,拼接起来的串就是原串的一个前缀,或者是两个前缀拼接起来
考虑第一种情况,本质上是对于 \(AC\) 自动机中每一个 \(fail \neq root\) 的点,其到 \(root\) 的路径代表的前缀就是一个合法的答案
对于第二种情况,根据 \(AC\) 自动机的性质,匹配串和合法路径一一对应,所以问题可以转化为对合法路径计数
于是考虑在 \(AC\) 自动机上枚举第一个串,通过 \(dp\) 处理出每一个 \(Trie\) 树节点作为路径终点的答案,通过走树边和 \(fail\) 边来转移
设 \(f[i][j][k]\) 表示总长度 \(i\) 的串走到了节点 \(j\) ,枚举的第一个串的长度为 \(k\) 的答案
转移就直接走 \(Trie\) 图的边转移,但要保证任意时刻拼接起来的串长要能够等于 \(i\) ,也就是 \(dep(j) + k > i\)
但是这样的复杂度是 \(O(n\times60^2\times26)\) 的,时间复杂度不能够接受,考虑对状态进行简化
观察发现,将不等式稍微加变换就是 \(dep(j) > i - k\) ,那么只需要记录 \(f[i][j]\) 表示第二个串长为 \(i\) ,当前到达了节点 \(j\) 的方案数,现在复杂度是 \(O(n \times 26 \times 60)\)
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
#define int ll
#define par pair<int, int>
#define mp make_pair
#define fi first
#define se second
const int N = 3000005;
char s[N];
int f[65][N], n;
struct ACautomaton{
queue<int> q; int ch[N][26], dep[N], nxt[N][26], fail[N], size;
inline ACautomaton(){
for(int i = 0; i < 26; i++) nxt[0][i] = 1; size = 1;
}
inline int newnode(int x){ return dep[++size] = x, size; }
inline void ins(char *s){
int p = 1, len = strlen(s);
for(int i = 0; i < len; i++){
int c = s[i] - 'a';
if(!ch[p][c]) ch[p][c] = nxt[p][c] = newnode(i + 1);
p = ch[p][c];
}
}
inline void build(){
for(q.push(1); !q.empty(); ){
int u = q.front(); q.pop();
for(int i = 0; i < 26; i++){
int v = nxt[u][i];
if(!v) nxt[u][i] = nxt[fail[u]][i];
else fail[v] = nxt[fail[u]][i], q.push(v);
}
}
}
inline void solve(){
int ans = 0;
for(int i = 2; i <= size; i++) ans += (fail[i] != 1);
for(int i = 1; i <= size; i++)
for(int j = 0; j < 26; j++)
if(!ch[i][j] && nxt[i][j] != 1) f[1][nxt[i][j]]++;
for(int i = 1; i <= 60; i++)
for(int j = 1; j <= size; j++) if(f[i][j]){
for(int c = 0; c < 26; c++)
if(dep[nxt[j][c]] > i) f[i+1][nxt[j][c]] += f[i][j];
}
for(int i = 1; i <= 60; i++)
for(int j = 1; j <= size; j++) ans += f[i][j];
cout << ans;
}
}van;
signed main(){
read(n);
for(int i = 1; i <= n; i++) scanf("%s", s), van.ins(s);
van.build(), van.solve();
return 0;
}
「BZOJ 4502」串的更多相关文章
- 「BZOJ 2534」 L - gap字符串
「BZOJ 2534」 L - gap字符串 题目描述 有一种形如 \(uv u\) 形式的字符串,其中 \(u\) 是非空字符串,且 \(v\) 的长度正好为 \(L\), 那么称这个字符串为 \( ...
- 「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\) ...
- 「BZOJ 4289」 PA2012 Tax
「BZOJ 4289」 PA2012 Tax 题目描述 给出一个 \(N\) 个点 \(M\) 条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点 \(1\) 到点 \( ...
- 「BZOJ 2956」模积和
「BZOJ 2956」模积和 令 \(l=\min(n,m)\).这个 \(i\neq j\) 非常不优雅,所以我们考虑分开计算,即: \[\begin{aligned} &\sum_{i=1 ...
- Solution -「BZOJ 3812」主旋律
\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...
- 「BZOJ 1001」狼抓兔子
题目链接 luogu bzoj \(Solution\) 这个貌似没有什么好讲的吧,直接按照这个给的图建图就好了啊,没有什么脑子,但是几点要注意的: 建双向边啊. 要这么写,中间还要写一个\(whil ...
- 「BZOJ 5188」「Usaco2018 Jan」MooTube
题目链接 luogu bzoj \(Describe\) 有一个\(n\)个节点的树,边有权值,定义两个节点之间的距离为两点之间的路径上的最小边权 给你\(Q\)个询问,问你与点\(v\)的距离大于等 ...
- 「BZOJ 2342」「SHOI 2011」双倍回文「Manacher」
题意 记\(s_R\)为\(s\)翻转后的串,求一个串最长的形如\(ss_Rss_R\)的子串长度 题解 这有一个复杂度明显\(O(n)\)的做法,思路来自网上某篇博客 一个双倍回文串肯定当且仅当本身 ...
随机推荐
- 旋转3D立方体
<!DOCTYPE html><html><head> <title>css-3d-盒子</title> <meta charset= ...
- redis笔记之两种持久化备份方式(RDB & AOF)
Redis支持的两种持久化备份方式(RDB & AOF) redis支持两种持久化方式,一种是RDB,一种是AOF. RDB是根据指定的规则定时将内存中的数据备份到硬盘上,AOF是在每次执行命 ...
- IE6透明PNG解决方案
IE6不支持PNG-24图片一直困扰很多人,但是可以通过IE的独有的滤镜来解决,解决的方案很多,比如:将滤镜写在CSS里,还可以写成单独的 Javascript文件,本来认为推荐两种做法:第一种,将所 ...
- RMQ之ST求区间最大值
题目链接:https://cn.vjudge.net/problem/HRBUST-1188 每一次按照二进制的方式进行更新,二维数组dp [i] [j],i表示下标,j表示从i 开始的往后移动2的j ...
- Test plan
Options for Test Strategy: 1. Regular test: all the planned test cases will be executed 2. Extented ...
- 【shell】shell编程总结
总结一下在写shell脚本时的常见注意事项: 1.shell脚本中的命令最好用命令的全路径,如果不知道全路径可以用which cmd查找命令的全路径. 2.shell脚本中定义环境变量用export ...
- elk系列5之syslog的模块使用【转】
preface rsyslog是CentOs系统自带的的一个日志工具,那么我们就配置logstash来接受rsyslog的日志. logstash的syslog模块 linux-node2上操作log ...
- PDFRender4NET的使用之pdf转图片
同样的需要第三方的.dll,http://www.o2sol.com/pdfview4net/download.htm using O2S.Components.PDFRender4NET; usin ...
- Tomcat: Connector中HTTP与AJP差别与整合
apache tomcat 整合(ajp proxy, http proxy) 1.软件: apache: httpd-2.2.17-win32-x86-openssl-0.9.8o.msi tomc ...
- Idea安装Scala插件(转)
原文链接:http://blog.csdn.net/a2011480169/article/details/52712421 参考博客: 1.http://wwwlouxuemingcom.blog. ...