JZOJ 3648【GDOI2014】beyond
来源:互联网 发布:wdi数据库怎么用 编辑:程序博客网 时间:2024/05/17 04:21
Description:
Input:
第一行:包含一个整数N。
第二行:包含一个长度为N的字符串,字符串中只包含小写字母。
第三行:包含一个长度为N的字符串,字符串中只包含小写字母。
Output:
输出答案只包含一个数字L,表示圆环最大可能有的格子数。
Sample Input:
输入1:
5
abcdx
cdabz
输入2:
4
abcd
cdab
Sample Output:
输出1:
4
输出2:
4
Data Constraint:
对于20% 的数据,1 <= N <= 5,000
对于50% 的数据,1 <= N <= 600,000
对于100% 的数据,1 <= N <= 2,000,000
题目大意:
给出两个长度为n的字符串a,b,求最大的L,使得a[1..L]和b[1..L]是循环同构的(展开后是一个同一个环)。
1 <= n <= 2000000
题解:
算是exkmp比较裸的题了。
设exkmpA[i]表示a[i..n]与b的lcp。
exkmpB同理。
我们枚举a串的一个位置k,那我们需要在exkmpB[1..exkmpA[k] +1]中找到一个最大的j,使得exkmpB[j] >= k。
exkmpA、exkmpB是很好求的。
关键在于如何找到j。
我们很容易想到线段树维护一个exkmpB的最大值,然后使用线段树二分。
可是不要忘记n是2000000.
O(n logn)只有50分。
由于我们可以从左到右枚举k,我们想象一个数组c,c[i]表示exkmpB[i]是否大于等于当前k,要找到最大的j,就相当于找c[exkmpA[k]+1]往左边(可以是它本身)的第一个1,这个东西我们可以用并查集维护,至于c[i]的修改用前向星解决。
JZOJ的栈没良心,逼得我打了人工栈并查集。
Code:
#include<cstdio>#include<cstring>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define min(a, b) ((a) < (b) ? (a) : (b))#define max(a, b) ((a) > (b) ? (a) : (b))using namespace std;const int Maxn = 2000005;int n, ans; char a[Maxn], b[Maxn];int next[Maxn], exkmp[Maxn];int f[Maxn], z[Maxn], bz[Maxn];int final[Maxn], nt[Maxn], to[Maxn], tot;int find(int x) { z[++ z[0]] = x; bz[1] = 0; while(z[0]) { if(!bz[z[0]]) { if(f[z[z[0]]] == z[z[0]]) { z[0] --; } else { bz[z[0]] = 1; z[++ z[0]] = f[z[z[0] - 1]]; bz[z[0]] = 0; } } else f[z[z[0]]] = f[z[z[0] + 1]], z[0] --; } return f[x];}void link(int x, int y) { nt[++ tot] = final[x], to[tot] = y, final[x] = tot; }void Get_next(char s[]) { next[1] = n; int a = 1; while(a < n && s[a + 1] == s[a]) a ++; next[2] = a - 1, a = 2; fo(i, 3, n) { int p = a + next[a] - 1, l = next[i - a + 1]; if(i + l - 1 >= p) { int j = (p - i + 1) > 0 ? (p - i + 1) : 0; while(i + j - 1 < n && s[j + 1] == s[i + j]) j ++; next[i] = j, a = i; } else next[i] = l; }} void Get_exkmp(char s[], char t[]) { int a = 1; while(a < n && s[a + 1] == t[a + 1]) a ++; exkmp[1] = a - 1, a = 1; fo(i, 2, n) { int p = a + exkmp[a] - 1, l = next[i - a + 1]; if(i + l - 1 >= p) { int j = (p - i + 1) > 0 ? (p - i + 1) : 0; while(i + j - 1 < n && j < n && s[i + j] == t[j + 1]) j ++; exkmp[i] = j, a = i; } else exkmp[i] = l; if(i + exkmp[i] - 1 > n) exkmp[i] = n - i + 1; }}void delet(int x) { f[x] = find(f[x - 1]);}void End() { fo(i, 1, n) f[i] = i; fo(i, 1, n) { int j = find(exkmp[i] + 1); if(j) ans = max(ans, i + j - 2); for(int k = final[i]; k; k = nt[k]) delet(to[k]); } printf("%d", ans);}int main() { scanf("%d", &n); scanf("%s", a + 1); scanf("%s", b + 1); Get_next(a); Get_exkmp(b, a); fo(i, 1, n) link(exkmp[i] + 1, i); Get_next(b); Get_exkmp(a, b); End();}
阅读全文
1 0
- JZOJ 3648【GDOI2014】beyond
- 【GDOI2014】beyond
- 【GDOI2014】beyond
- [JZOJ3648]【GDOI2014】beyond
- Jzoj3648 【GDOI2014】beyond
- JZOJ 3432. 【GDOI2014模拟】服务器
- jzoj. 3432. 【GDOI2014模拟】服务器
- JZOJ.3400【GDOI2014模拟】旅行 解题报告
- JZOJ.3431【GDOI2014模拟】网格 解题报告
- JZOJ.3432【GDOI2014模拟】服务器 解题报告
- jzoj 3583. 【GDOI2014模拟】小A的树
- [jzoj]3432. 【GDOI2014模拟】服务器(斜率优化或单调队列)
- Beyond
- BEYOND
- Beyond
- beyond
- Beyond
- beyond
- Kotlin学习笔记-基础语法
- 笔记2
- 多线程
- 接口
- java中字符串和函数的基础应用
- JZOJ 3648【GDOI2014】beyond
- 【模拟】17.6.1 异或和 题解
- 读《大型网站技术架构》
- 笔记3
- mysql 注意点汇总
- bzoj1179 [Apio2009]Atm
- 异常
- html td文字垂直对齐
- 575. Distribute Candies