[BZOJ4212]神牛的养成计划

试题描述

Hzwer 成功培育出神牛细胞,可最终培育出的生物体却让他大失所望......

后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的......

黄学长现在知道了 \(N\) 个细胞的 DNA 序列,它们是若干个由小写字母组成的字符串。一个优秀的基因是两个字符串 \(s_1\) 和 \(s_2\),当且仅当 \(s_1\) 是某序列的前缀的同时,\(s_2\) 是这个序列的后缀时,hzwer 认为这个序列拥有这个优秀基因。

现在黄学长知道了 \(M\) 个优秀基因 \(s_1\) 和 \(s_2\),它们想知道对于给定的优秀基因,有多少个细胞的 DNA 序列拥有它。

输入

第一行:\(N\),表示序列数

接下来 \(N\) 行,每行一个字符串,代表 \(N\) 个 DNA 序列,它们的总长为 \(L_1\)

接下来一个 \(M\),表示询问数

接下来 \(M\) 行,每行两个字符串 \(s_1\) 和 \(s_2\),由一个空格隔开,hzwer 希望你能在线回答询问,所以 \(s_1\) 等于“\(s_1\)”的所有字符按字母表的顺序向后移动 \(ans\) 位(字母表是一个环),\(ans\) 为上一个询问的答案,\(s_2\) 同理。例如 \(ans=2, “s_1”=qz\) 则 \(s_1=sb\)。对于第一个询问,\(ans=0\),\(s_1\) 和 \(s_2\) 的总长度为 \(L_2\)

输出

输出有 \(p\) 行,YesNo.

输入示例

10
emikuqihgokuhsywlmqemihhpgijkxdukjfmlqlwrpzgwrwozkmlixyxniutssasrriafu
emikuqihgokuookbqaaoyiorpfdetaeduogebnolonaoehthfaypbeiutssasrriafu
emikuqihgokuorocifwwymkcyqevdtglszfzgycbgnpomvlzppwrigowekufjwiiaxniutssasrriafu
emikuqihgokuorociysgfkzpgnotajcfjctjqgjeeiheqrepbpakmlixyxniutssasrriafu
emikuqihgokuorociysgfrhulymdxsqirjrfbngwszuyibuixyxniutssasrriafu
emikuqihgokuorguowwiozcgjetmyokqdrqxzigohiutssasrriafu
emikuqihgokuorociysgsczejjmlbwhandxqwknutzgdmxtiutssasrriafu
emikuqihgokuorociysgvzfcdxdiwdztolopdnboxfvqzfzxtpecxcbrklvtyxniutssasrriafu
emikuqihgokuorocsbtlyuosppxuzkjafbhsayenxsdmkmlixyxniutssasrriafu
emikuqihgokuorociysgfjvaikktsixmhaasbvnsvmkntgmoygfxypktjxjdkliixyxniutssasrriafu
10
emikuqihgokuorociysg yxniutssasrriafu
aiegqmedckgqknky eqpoowonnewbq
xfbdnjbazhdnhkhvb qrqgbnmlltlkkbtyn
bjfhrnfedlhrlolzfv qppxpoofxcr
zhdfpldcbjf stsidponnvnmmdvap
zhdfpldcbjfpjmjxdt gdstsidponnvnmmdvap
dlhjtphgfnjtnqnbhxr wxwmhtsrrzrqqhzet
bjfhrnfedlhrlolzfv frqppxpoofxcr
zhdfpldcbjf dponnvnmmdvap
ucyakgyxweakehes nondykjiiqihhyqvk

输出示例

4
7
3
5
5
1
3
5
10
4

数据规模及约定

\(N \le 2000\)

\(L_1 \le 2000000\)

\(M \le 100000\)

\(L_2 \le 2000000\)

题解

直接 \(O(NM)\) 哈希看上去复杂度是对的,但是大视野老爷机可能不是很资瓷……

其实并不明白 \(N\) 为什么不给到和 \(M\) 同阶,反正复杂度都是 \(O(L_1 + L_2)\) 的。

考虑建立 trie 树,这样直接解决了前缀的问题,我们可以发现所有合法的串一定都在 trie 树的某个子树中,而一个子树可以变成一段区间,那么我们就是要求一段区间内满足后缀是 \(s_2\) 的串有多少个。这样一来我们可以按照每个串在 trie 树中的 dfs 序,从小到大按反串建立可持久化 trie,这样对于一个区间直接就是两个版本的 trie 相减。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxl 2000010
#define maxln 2100010
#define maxa 26 char S[maxl], S2[maxl];
int str[maxl], str2[maxl]; struct Trie {
int ToT, ch[maxl][maxa], fa[maxl], tot[maxl], clo, dl[maxl], dr[maxl], perm[maxl];
Trie() { ToT = 1; }
void Insert(char *S) {
int n = strlen(S), u = 1;
rep(i, 0, n - 1) {
int x = S[i] - 'a';
if(!ch[u][x]) fa[ch[u][x] = ++ToT] = u;
u = ch[u][x];
}
tot[u]++;
return ;
}
void build(int u) {
perm[dl[u] = ++clo] = u;
rep(c, 0, maxa - 1) if(ch[u][c]) build(ch[u][c]);
dr[u] = clo;
return ;
}
} sol; struct RTrie {
int ToT, ch[maxln][maxa], rt[maxln], siz[maxln];
RTrie() { ToT = rt[0] = 1; }
void Insert(int id, char *S, int v) {
siz[++ToT] = siz[rt[id-1]] + v; memcpy(ch[ToT], ch[rt[id-1]], sizeof(ch[ToT])); rt[id] = ToT;
// printf("siz[%d] = %d (+ %d)\n", ToT, siz[ToT], v);
int n = strlen(S), u = rt[id];
rep(i, 0, n - 1) {
int x = S[i] - 'a';
siz[++ToT] = siz[ch[u][x]] + v; memcpy(ch[ToT], ch[ch[u][x]], sizeof(ch[ToT])); ch[u][x] = ToT;
u = ch[u][x];
}
return ;
}
int query(int *s1, int *s2, int l1, int l2) {
int u = 1, vl, vr;
rep(i, 0, l1 - 1) u = sol.ch[u][s1[i]];
vl = rt[sol.dl[u]-1]; vr = rt[sol.dr[u]];
// printf("%d: [%d, %d] %d %d | %d %d\n", u, sol.dl[u], sol.dr[u], vl, vr, siz[vl], siz[vr]);
dwn(i, l2 - 1, 0) vl = ch[vl][s2[i]], vr = ch[vr][s2[i]];
// printf("vl, vr: %d, %d %d %d\n", vl, vr, siz[vl], siz[vr]);
return siz[vr] - siz[vl];
}
} rsol; int main() {
int n = read();
rep(i, 1, n) scanf("%s", S), sol.Insert(S); sol.build(1);
rep(i, 1, sol.ToT) {
int u = sol.perm[i], l = 0;
if(!sol.tot[u]) {
rsol.rt[i] = rsol.rt[i-1];
continue;
}
int v = sol.tot[u];
while(u > 1) {
rep(c, 0, maxa - 1) if(sol.ch[sol.fa[u]][c] == u){ S[l++] = c + 'a'; break; }
u = sol.fa[u];
}
S[l] = 0;
// printf("rsol.Insert(%d, %s)\n", i, S);
rsol.Insert(i, S, v);
} int q = read(), lstans = 0;
while(q--) {
scanf("%s%s", S, S2);
int l = strlen(S), l2 = strlen(S2);
rep(i, 0, l - 1) str[i] = (S[i] - 'a' + lstans) % maxa;
rep(i, 0, l2 - 1) str2[i] = (S2[i] - 'a' + lstans) % maxa;
printf("%d\n", lstans = rsol.query(str, str2, l, l2));
} return 0;
}

[BZOJ4212]神牛的养成计划的更多相关文章

  1. BZOJ4212 神牛的养成计划 (字典树,bitset)

    题面 Description Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望- 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了, ...

  2. 【BZOJ4212】神牛的养成计划 Trie树+可持久化Trie树

    [BZOJ4212]神牛的养成计划 Description Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变 ...

  3. 【BZOJ-4212】神牛的养成计划 Trie树 + 可持久化Trie树

    4212: 神牛的养成计划 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 136  Solved: 27[Submit][Status][Discus ...

  4. BZOJ 4212: 神牛的养成计划

    4212: 神牛的养成计划 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 142  Solved: 30[Submit][Status][Discus ...

  5. 【bzoj4212】神牛的养成计划

    Portal --> bzoj4212 Description ​ 给你\(n\)个字符串,接下来有\(m\)个询问,每个询问由两个给定的字符串\(s_1\)和\(s_2\)组成,对于每个询问输 ...

  6. BZOJ.4212.神牛的养成计划(Trie 可持久化Trie)

    BZOJ 为啥hzw的题也是权限题啊 考虑能够匹配\(s1\)这一前缀的串有哪些性质.对所有串排序,能发现可以匹配\(s1\)的是一段区间,可以建一棵\(Trie\)求出来,设为\([l,r]\). ...

  7. BZOJ 4212: 神牛的养成计划 可持久化trie+trie

    思路倒是不难,但是这题卡常啊 ~ code: #include <bits/stdc++.h> #define N 2000004 #define M 1000005 #define SI ...

  8. Web前端开发工程师养成计划【转载】

    Web前端开发工程师养成计划(入门篇) 最原始的忠告:这个世界上有想法的人很多,但是有想法又能实现它的人太少! 首先要感谢伟大的Web2.0概念.产品概念.用户体验概念.jQuery插件,是它们在中国 ...

  9. 高手养成计划基础篇-Linux第二季

    高手养成计划基础篇-Linux第二季   本文来源:i春秋社区-分享你的技术,为安全加点温度   前言 前面我们学习了文件处理命令和文件搜索命令,简单的了解了一下Linux,但是仅仅了解这样还不行,遇 ...

随机推荐

  1. xml的schema约束(Java)

    1.schema约束 *dtd语法:<!ELEMENT 元素名称 约束> schema符合xml的语法,是xml语句. 一个xml文件中可以有多个schema,多个schema使用名称空间 ...

  2. Windows下安装Mysql5.5.27(社区版)

    所有平台的 MySQL 下载地址为: MySQL 下载. 挑选你需要的 MySQL Community Server 版本及对应的平台. 运行mysql-5.5.27-win32.msi 进入欢迎界面 ...

  3. python应用:经纬度匹配

    需要安装第三方包:requests 本次经纬度匹配采用高德地图api,首先将gps坐标转化为高德地图的经纬度坐标,然后再根据转化后的坐标进行匹配. 本次匹配主要是获取距离给定经纬度最近的poi点地址信 ...

  4. Leecode刷题之旅-C语言/python-14.最长公共前缀

    /* * @lc app=leetcode.cn id=14 lang=c * * [14] 最长公共前缀 * * https://leetcode-cn.com/problems/longest-c ...

  5. ssh安装和使用

    1.基础知识 ssh用于远程登陆,linux默认安装了client,如果需要被登陆则需要安装 server 2.安装 apt-get install openssh-server 检查是否安装成功 a ...

  6. go学习笔记-程序测试

    程序测试 测试是一个可重复的过程,它验证某个东西是否按预期工作.一般通过 go test 进行测试,步骤如下 首先,是我们的文件名.Go 要求所有的测试都在以 _test.go 结尾的文件中.这使得我 ...

  7. Altium Designer -- 精心总结

    如需转载请注明出处:http://blog.csdn.NET/qq_29350001/article/details/52199356 以前是使用DXP2004来画图的,后来转行.想来已经有一年半的时 ...

  8. 10-mongodb启动错误

    1.error信息 python@ubuntu:~$ mongod --22T17:: I CONTROL [initandlisten] MongoDB starting : pid= port= ...

  9. 如何删除TFS项目

    TFS是先建集合,再在集合下面建项目.删除的时候,需要先删除项目,再删除集合,然后重新建.具体步骤如下: 1.删除项目        删除项目必须通过命令来进行删除,调用TFSDeleteProjec ...

  10. android service笔记

    1.service 默认在主线程运行,所以不能在service中直接做访问网络,操作文件等耗时操作,要另外开启线程 2.通过startservice开启的服务,一旦服务开启,这个服务和开启他的调用者之 ...