BZOJ3277——串
0、题意:给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)。
1、分析:这个题我问了吴大爷做法
首先建立后缀自动机,然后利用离线搞出每一个节点在多少个串中,这个用树状数组统计一下就好,和BZOJ2780一样,然后如果这个节点在不少于x个串中,我们把这个点的value赋值成这个节点父亲边的字符个数,否则为0。随后我们预处理一下从根到每个节点路径上的权值和。于是每个字符串的答案等于所有这个字符串的后缀节点的从根到该节点的权值和。
然后这个题就解决了
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 200010
#define LL long long
inline int read(){
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
struct node{
int tranc[27], fa, len;
} a[202010];
int cnt, tail;
char s[202010];
int p, nq, q, np;
int in[M], out[M], seg[M], num;
int C[M], v[M];
int lastins[M];
int sum[M];
struct gragh{
int head[M], to[M], Next[M], tot;
inline void init(){
memset(head, -1, sizeof(head));
tot = 0;
}
inline void add(int u, int v){
++ tot;
Next[tot] = head[u];
head[u] = tot;
to[tot] = v;
}
} w, G, sam;
struct Query{
int id, l, r;
inline bool operator < (const Query& rhs) const{
return r < rhs.r;
}
} S[M];
inline void insert(int k, int op){
p = tail;
if(a[p].tranc[k] != 0){
q = a[p].tranc[k];
if(a[q].len == a[p].len + 1) tail = q;
else{
a[nq = ++ cnt] = a[q];
a[q].fa = nq;
a[nq].len = a[p].len + 1;
for(; a[p].tranc[k] == q; p = a[p].fa) a[p].tranc[k] = nq;
tail = nq;
}
}
else{
np = ++ cnt;
a[np].len = a[tail].len + 1;
for(p = tail; p && !a[p].tranc[k]; p = a[p].fa) a[p].tranc[k] = np;
if(!p) a[np].fa = 1;
else{
q = a[p].tranc[k];
if(a[q].len == a[p].len + 1) a[np].fa = q;
else{
a[nq = ++ cnt] = a[q];
a[q].fa = a[np].fa = nq;
a[nq].len = a[p].len + 1;
for(; a[p].tranc[k] == q; p = a[p].fa) a[p].tranc[k] = nq;
}
}
tail = np;
}
w.add(tail, op);
sam.add(op, tail);
}
inline void dfs(int x){
in[x] = ++ num; seg[num] = x;
for(int i = G.head[x]; i != -1; i = G.Next[i]){
dfs(G.to[i]);
}
out[x] = num;
}
inline void change(int x, int d){
for(; x <= cnt; x += (x & -x)) C[x] += d;
}
inline int ask(int x){
int ret = 0;
for(; x > 0; x -= (x & -x)) ret += C[x];
return ret;
}
inline void dfs2(int x){
v[x] += v[a[x].fa];
for(int i = G.head[x]; i != -1; i = G.Next[i]) dfs2(G.to[i]);
}
int main(){
int n = read(), lim = read();
cnt = 1;
G.init(); w.init(); sam.init();
for(int i = 1; i <= n; i ++){
scanf("%s", s + 1);
tail = 1;
int len = strlen(s + 1);
for(int j = 1; j <= len; j ++){
insert(s[j] - 'a' + 1, i);
}
}
for(int i = 1; i <= cnt; i ++){
if(a[i].fa != 0) G.add(a[i].fa, i);
}
dfs(1);
for(int i = 1; i <= cnt; i ++) S[i] = (Query){i, in[i], out[i]};
sort(S + 1, S + cnt + 1);
int k = 1;
for(int i = 1; i <= cnt; i ++){
for(int j = w.head[seg[i]]; j != -1; j = w.Next[j]){
if(lastins[w.to[j]]) change(lastins[w.to[j]], -1);
change(lastins[w.to[j]] = i, 1);
}
while(S[k].r == i) sum[S[k].id] = ask(S[k].r) - ask(S[k].l - 1), k ++;
}
for(int i = 1; i <= cnt; i ++){
if(sum[i] >= lim) v[i] = a[i].len - a[a[i].fa].len;
else v[i] = 0;
}
dfs2(1);
LL ans = 0;
for(int i = 1; i <= n; i ++){
if(i > 1) printf(" ");
ans = 0;
for(int j = sam.head[i]; j != -1; j = sam.Next[j]) ans += v[sam.to[j]];
printf("%lld", ans);
}
return 0;
}
BZOJ3277——串的更多相关文章
- BZOJ3473&&BZOJ3277串
BZOJ3473&&BZOJ3277串 题面 自己找去 HINT 对于所有串建立一个广义后缀自动机,对于每一个节点开一个set表示这个节点接受的子串在哪些串里出现过,然后在parent ...
- BZOJ3277 串(后缀数组+二分答案+主席树)
因为不会SAM,考虑SA.将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法. 对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了.这是 ...
- bzoj3277 串 (后缀数组+二分答案+ST表)
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
- bzoj3473: 字符串 && bzoj3277串
3473: 字符串 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 121 Solved: 53[Submit][Status][Discuss] D ...
- 【文文殿下】[BZOJ3277] 串
Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身) Input 第一行两个整数n,k ...
- BZOJ3277 串 【广义后缀自动机】
Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...
- bzoj3473字符串&bzoj3277串
题意:给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串.注意本质相同的子串多次出现算多次,如1 1 aaa这组数据答案为6,贡献1WA.代码里有些部分是为了 ...
- BZOJ3277: 串(广义后缀自动机)
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1196 Solved: 478[Submit][Status][Discuss] Descripti ...
- BZOJ3277 串(后缀自动机)
对多串建立SAM的一种方法是加分隔符.于是加完分隔符建出SAM. 考虑统计出每个节点被多少个串包含.让每个串各自在SAM上跑,跑到一个节点就标记(显然一定会完全匹配该节点,因为是对包含其的串建的SAM ...
随机推荐
- php 设计模式 例子
加载类:include("./Ren.class.php");include "./Ren.class.php"; require("./Ren.cl ...
- coreseek 中文搜索和高亮
配置文件 # # Minimal Sphinx configuration sample (clean, simple, functional) # source post { type = mysq ...
- codeforces 711B - Chris and Magic Square(矩阵0位置填数)
题目链接:http://codeforces.com/problemset/problem/711/B 题目大意: 输入 n ,输入 n*n 的矩阵,有一个占位 0 , 求得将 0 位置换成其他的整数 ...
- 解决问题--VS2012中一个Panel覆盖另一个Panel时拖动时容易造成两个控件成父子关系的避免
在*.Designer.cs中,假如想把panel1覆盖到panel2上,但是VS自动让panel1成为panel2的子控件了,在文件中会有this.panel2.Controls.Add(this. ...
- GLEW OpenGL Access violation when using glGenVertexArrays
http://stackoverflow.com/questions/20766864/glew-opengl-access-violation-when-using-glgenvertexarray ...
- 使用 Object.create 创建对象,super 关键字,class 关键字
ECMAScript 5 中引入了一个新方法:Object.create().可以调用这个方法来创建一个新对象.新对象的原型就是调用 create 方法时传入的第一个参数: var a = {a: 1 ...
- 使用wp_editor函数实现可视化编辑器
在最近的wp项目中遇到了需要使用可视化编辑器来接收用户的输入,正好就研究了一下wp_editor这个函数的用法,利用这个函数能很方便的把textarea文本域变成可视化编辑器. Wp_editor函数 ...
- 仿微信底部自定义菜单 移动web
最近在做微信开发,要实现微信公众号改版—-改成微官网形式,即移动web页面中实现公众号的主页面,包括了公众号的菜单在底部显示 本文针对仿公众号底部菜单这个功能实现进行总结.实现采用html和css.J ...
- Mount挂载命令使用方法
语法: mount -t 类型 -o 挂接方式 源路径 目标路径 -t 详细选项: 光盘或光盘镜像:iso9660 DOS fat16文件系统:msdos Windows 9x fat32文件 ...
- mysql配置mysql-proxy读写分离
MySQL配置读写分离 192.168.23.131与192.168.23.132两台服务器,131是主,132是从,131是读写,132是只读.myql-proxy的IP是192.168.23.13 ...