【GDOI2017 day1】微信
来源:互联网 发布:英国谢菲尔德大学知乎 编辑:程序博客网 时间:2024/05/21 16:56
题目大意:
给出20棵trie。
每次询问问某几棵trie的子串的lcs。
总长小于10^6。
题解:
已经退役的wyx当时说:“又是裸题,真没意思。”
呵呵。可惜初二的我连后缀自动机是什么都不知道,只会那个弱弱的AC自动机。
如果没有每次的询问,那么这个跟SPOJ的lcs2没有什么区别,这个只是广义后缀自动机。
前一篇博客已经讲过,广义后缀自动机和正常的真的没有毛线区别。
现在重点在于每次询问某几棵怎么办?
只有20个trie启发我们暴力一次算出所有的答案,存下来,O(1)回答。
做法是合并二十个trie。
每个点存一个二进制状态表示从根到它的路径是哪些原来的trie的公共部分。
那么我们把这个点丢到SAM里去,它对应状态所代表的子串显然可以在这个二进制状态的基础上,所以or一下。
由于一个状态的right一定是虚边父亲的right的子集,所以Turpo一下,给它的父亲也or一下。
每个状态x所代表的最大长度是step[x],所以去个max。
最后注意如果有二进制状态x,y,x是y的子集,既然y所对应的lcs有这么长,x更少,那么一定也可以。所以-每个二进制状态也要给子状态传一下答案。
时间复杂度是
Code:
#include<cstdio> #include<cstring>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define max(a, b) ((a) > (b) ? (a) : (b))using namespace std;const int N = 1e6 + 5;int a2[21];int n, Q, x; char s[N];int next[N][26], tot, last[N], fa[N], z[N];int ans[1048577];struct suffix_automation { int tot, fa[N * 2], son[N * 2][26], dep[N * 2], z[N * 2]; #define push(v) dep[++ tot] = v; int Extend(int last, int c, int zz) { push(dep[last] + 1); int p = last, np = tot; z[np] |= zz; for(; p && !son[p][c]; p = fa[p]) son[p][c] = np; if(!p) fa[np] = 1; else { int q = son[p][c]; if(dep[p] + 1 < dep[q]) { push(dep[p] + 1); int nq = tot; z[nq] |= zz; memcpy(son[nq], son[q], sizeof son[q]); fa[nq] = fa[q]; fa[q] = fa[np] = nq; for(; son[p][c] == q; p = fa[p]) son[p][c] = nq; } else fa[np] = q; } last = np; return last; } int d[N * 2], r[N * 2]; void Turpo() { fo(i, 1, tot) r[fa[i]] ++; int st = 1, en = 0; fo(i, 1, tot) if(!r[i]) d[++ en] = i; for(; st <= en; st ++) { int x = d[st]; z[fa[x]] |= z[x]; if(!(-- r[fa[x]])) d[++ en] = fa[x]; } } void Gao() { fo(i, 1, tot) ans[z[i]] = max(ans[z[i]], dep[i]); for(int i = a2[n] - 1; i >= 1; i --) { fo(j, 0, n - 1) if(i & a2[j]) ans[i - a2[j]] = max(ans[i - a2[j]], ans[i]); } }} suf;void dg(int x, int F, int c) { if(x == 0) { last[x] = suf.tot = 1; } else { last[x] = suf.Extend(last[F], c, z[x]); } fo(j, 0, 25) if(next[x][j]) { int y = next[x][j]; dg(y, x, j); }}int main() { freopen("wechat.in", "r", stdin); freopen("wechat.out", "w", stdout); a2[0] = 1; fo(i, 1, 20) a2[i] = a2[i - 1] * 2; scanf("%d", &n); fo(i, 1, n) { scanf("%s", s); int m = strlen(s); x = 0; z[x] |= a2[i - 1]; fo(j, 0, m - 1) { if(s[j] == '<') { x = fa[x]; } else { int c = s[j] - 'a'; if(next[x][c] == 0) next[x][c] = ++ tot, fa[tot] = x; x = next[x][c]; z[x] |= a2[i - 1]; } } } dg(0, 0, 0); suf.Turpo(); suf.Gao(); for(scanf("%d", &Q); Q; Q --) { scanf("%s", s); x = 0; fo(i, 0, n - 1) x += a2[i] * (s[i] == '1'); printf("%d\n", ans[x]); }}
阅读全文
1 0
- 【GDOI2017 day1】微信
- 【GDOI2017 day1】微信
- 【GDOI2017 day1】微信
- 【JZOJ5098】【GDOI2017 day1】微信
- 【jzoj5098】【GDOI2017 day1】【微信】【tire上建sam】
- 【GDOI2017 day1 T3】微信 && SAM学习小记
- 【GDOI2017 day1】取石子游戏
- 【JZOJ5096】【GDOI2017 day1】房屋购置
- 【GDOI2017第二轮模拟day1】最长路径
- 【GDOI2017第二轮模拟day1】公路建设
- 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设
- [JZOJ5073]【GDOI2017第三轮模拟day1】影魔
- 【JZOJ5073】【GDOI2017第三轮模拟day1】影魔
- 【GDOI2017第四轮模拟day1】数列
- 【GDOI2017第四轮模拟day1】数列
- 【JZOJ5097】【GDOI2017 day1】取石子游戏
- {题解}[jzoj5097]【GDOI2017 day1】取石子游戏
- 微信公众号开发day1
- RestTemplate报错:no suitable HttpMessageConverter found for request type
- jzoj4243 【五校联考6day1】c 分块
- 剑指offer—链表中环的入口结点
- leetcode题解-146. LRU Cache
- 解决二级模态框关闭后,遮罩阴影依然存在,导致页面无法操作的BUG
- 【GDOI2017 day1】微信
- 单片机工程师转java程序员
- 透析适配器!
- 略微记录一下进度
- 图解设计模式
- java类的数组
- Hadoop 核心介绍
- 异步上传图片
- 分别用普通线性回归、岭回归、Lasso回归对boston房价进行预测,比较效果