[NOIP模拟] 字符串
来源:互联网 发布:找出两列中不同的数据 编辑:程序博客网 时间:2024/06/01 09:25
题目大意:
给出 n 个串(len <= 100), 再给出一个主串(len <= 100000), 给出 Q 次询问, 每次包括一个整数和一个字母,求主串在该整数位置将字母改为该字母后,n个串再主串中出现的次数。
输入简述 :
输入N <= 1000, Q <= 200000, N 个串,一个主串, Q次询问的整数和字母。
输出简述 :
最初值 + Q次询问的答案。
sample input :
3 5
ab
bc
abc
acbcb
2 b
3 c
4 a
1 b
3 a
sample ouput :
1
2
3
4
2
1
题解 :
提说这是 NOI 测试的签到题, 看来还是我太弱了。
我们考虑每次修改对答案的影响, 每次修改我们只会影响 pos - len + 1 到 pos + len - 1 的值, len 为非主串的字符串长度, pos为修改的位置, 于是我们只需要求出在这段区间的值就可以了, 那我们这里就会跑两边 AC 自动机,由于 len 不超过 100, 但我们会多次跳 fail, 所以这里可能会超, 于是我们考虑优化,我们将每个 AC 自动机上的点, 把他们所有的 fail 指针所跳的点的 cnt 都加起来,在预处理完成,这样我们就不用跳 fail 了。
代码 :
#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <cmath>#include <ctime>#include <map>#include <vector>#include <queue>#define clr(a) memset(a, 0, sizeof(a))using namespace std;inline int read() { int i = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } while(isdigit(ch)) { i = (i << 3) + (i << 1) + ch - '0'; ch = getchar(); } return i * f;}const int MAXN = 1e5 + 5;int mx;char s[MAXN];struct AC { int tot; struct point { int trans[26], cnt, fail; void clear() { clr(trans); cnt = fail = 0; } } tr[MAXN * 10]; inline void init() { for(int i = 0; i < 26; ++i) tr[0].trans[i] = 1; tr[tot = 1].clear(); } inline void insert(char * s) { int u = 1; int len = strlen(s + 1); mx = max(mx, len); for(int i = 1; i <= len; ++i) { if(!tr[u].trans[s[i] - 'a']) tr[tr[u].trans[s[i] - 'a'] = ++tot].clear(); u = tr[u].trans[s[i] - 'a']; } tr[u].cnt++; } inline void buildfail() { queue<int> q; q.push(1); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < 26; ++i) { int v = tr[u].fail; while(!tr[v].trans[i]) v = tr[v].fail; v = tr[v].trans[i]; int w = tr[u].trans[i]; if(w) tr[w].fail = v, q.push(w), tr[w].cnt += tr[v].cnt; else tr[u].trans[i] = v; } } } inline int solve(char *s, int l, int r) { int now = 1, ans = 0; for(int i = l; i <= r; ++i) { now = tr[now].trans[s[i] - 'a']; ans += tr[now].cnt; } return ans; }}acam;int main() { //freopen("1.in", "r", stdin); int n = read(), m = read(); acam.init(); for(int i = 1; i <= n; ++i) scanf("%s", s + 1), acam.insert(s); acam.buildfail(); scanf("%s", s + 1); int len = strlen(s + 1); int ans = acam.solve(s, 1, len); printf("%d\n", ans); while(m--) { int pos = read(); char ch = getchar(); int ans1 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1)); s[pos] = ch; int ans2 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1)); ans += ans2 - ans1; cout<<ans<<'\n'; }}
阅读全文
0 0
- 【Noip模拟】RP字符串
- [NOIP模拟] 字符串
- [NOIP模拟赛]相似字符串
- [Noip模拟题]RP字符串
- [NOIP模拟][AC自动机]字符串
- NOIP 模拟题 奇怪的字符串
- NOIP模拟:字符串(后缀数组)
- NOIP模拟 字符串【后缀数组+稀疏表】
- Noip模拟
- #NOIP模拟赛#相似字符串(树形DP + 状压)
- 【NOIP模拟】20151004模拟
- 【NOIP模拟】 20151005模拟
- 【NOIP模拟】 20151006模拟
- 【NOIP模拟】 20151007模拟
- 【NOIP模拟】20151014模拟
- 【NOIP模拟】20151015模拟
- NOIP-字符串
- 【09 NOIP 模拟】light
- Java 操作数组的流
- find_data_code_2d 一次性识别图片中的多个二维码
- Hadoop Yarn 框架原理及运作机制
- 10.15上课总结
- Java 编码表
- [NOIP模拟] 字符串
- 抽象数据类型ADT之栈的构建
- 30分钟利用oh-my-zsh打造漂亮的终端
- python selenium 自动化查询上海公交卡余额,并邮件通知
- 编程中使用函数的最佳理解
- 关于修改Matlab2014a菜单栏和命令窗口字体大小问题
- 计算机基础心得
- Android接入微信支付和支付宝支付(2)
- Java 按字节截取字符串