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();}
原创粉丝点击