https://www.lydsy.com/JudgeOnline/problem.php?id=4698
题意:求N个字符串中最长的相同字串的长度,相同的定义是:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。
这题的难点在于相同的定义,在这样的定义下一般的字符串匹配算法就不适用了。
但是可以通过一个操作,将前后相邻的字符串差分形成一个长度为len - 1的差分串,原来的相同下的定义就转为了差分串的完全相同,证明显然。
在这种情况下,再把字符串全部拼接起来,用特殊字符隔开,然后二分他们的长度去做后缀数组,看有没有相邻的一个区间同时满足长度最大并且包含所有K个字符串。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e6 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; int str[maxn],id[maxn]; int a[maxn],Height[maxn]; int tax[maxn],tp[maxn],sa[maxn],rak[maxn]; void Qsort(){ for(int i = 0; i <= M; i ++) tax[i] = 0; for(int i = 1; i <= N ; i ++) tax[rak[i]]++; for(int i = 1; i <= M ; i ++) tax[i] += tax[i - 1]; for(int i = N; i >= 1 ; i --) sa[tax[rak[tp[i]]]--] = tp[i]; } void SA(){ for(int i = 1; i <= N; i ++) rak[i] = str[i],tp[i] = i; Qsort(); for(int w = 1,p = 0; p < N;w <<= 1, M = p){ p = 0; for(int i = 1; i <= w; i ++) tp[++p] = N - w + i; for(int i = 1; i <= N ; i ++) if(sa[i] > w) tp[++p] = sa[i] - w; Qsort(); swap(tp,rak); rak[sa[1]] = p = 1; for(int i = 2; i <= N ; i ++){ rak[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w])?p:++p; } } } void Get_Height(){ int k = 0,j; for(int i = 1; i <= N; i ++){ if(k) k --; int j = sa[rak[i] - 1]; while(str[j + k] == str[i + k]) k++; Height[rak[i]] = k; } } int Stack[maxn]; bool vis[maxn]; bool check(int x){ int top = 0; int num = K; for(int i = 1; i <= K; i ++) vis[i] = 0; for(int i = 1; i <= N ; i ++){ if(Height[i] >= x){ if(!vis[id[sa[i]]]){ vis[id[sa[i]]] = 1; Stack[++top] = id[sa[i]]; num--; } if(!vis[id[sa[i - 1]]]){ vis[id[sa[i - 1]]] = 1; Stack[++top] = id[sa[i - 1]]; num--; } if(!num) return true; }else{ for(int j = 1; j <= top; j ++) vis[Stack[j]] = 0; top = 0; num = K; } } return false; } int solve(){ int l = 0,r = N - 1; int ans = 0; while(l <= r){ int m = l + r >> 1; if(check(m)){ ans = m; l = m + 1; }else{ r = m - 1; } } return ans + 1; } int main(){ Sca(K); N = 0; M = 2000; int MIN = INF; for(int i = 1; i <= K ; i ++){ int x = read(); a[1] = read(); for(int j = 2; j <= x; j ++){ a[j] = read(); str[++N] = a[j] - a[j - 1]; MIN = min(MIN,a[j] - a[j - 1]); id[N] = i; } str[++N] = ++M; id[N] = i; } if(MIN <= 0){ MIN = -MIN + 1; for(int i = 1; i <= N ; i ++) str[i] += MIN; M += MIN; } SA(); Get_Height(); Pri(solve()); return 0; }