题目大意:
就是现在给出两个只包含小写字母的字符串A, B, 一个正整数d, 求三元组(i, j, k)满足A[i, i + 1, .... i + k - 1] == B[j, j + 1, ... j + k - 1] , 且A[i, i + 1, ..., i + k - 1]是回文串, k >= d的三元组数量
大致思路:
做了2012长春那场区域赛的G题之后就会做这题了....
和长春那场的题一样首先对于字符串A, 其本质不同回文串数量是O(n)的(n是A的长度),. 那么Manacher + Hash找出所有不同的回文串, 然后后缀数组 + 二分找出A中这些回文串的数量, 对B进行同样的操作, 之后一一对应计算三元组数量即可, 这两题真是惊人的相似....
代码如下:
Result : Accepted Memory : 14012 KB Time : 472 ms
/* * Author: Gatevin * Created Time: 2015/3/29 20:23:15 * File Name: Chitoge_Kirisaki.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; typedef unsigned long long ulint; #define maxn 50010 #define rank rnk //原来这个UESTC的OJ用rank作为数组会CE... ulint xp[maxn], H[maxn]; const ulint seed = 50009; void initHash(char *s, int n) { H[0] = s[0] - 'a' + 1; for(int i = 1; i < n; i++) H[i] = H[i - 1]*seed + (ulint)(s[i] - 'a' + 1); return; } ulint askHash(int l, int r) { if(l == 0) return H[r]; return H[r] - H[l - 1]*xp[r - l + 1]; } int wa[maxn], wb[maxn], wv[maxn], Ws[maxn]; int cmp(int *r, int a, int b, int l) { return r[a] == r[b] && r[a + l] == r[b + l]; } void da(int *r, int *sa, int n, int m) { int *x = wa, *y = wb, *t, i, j, p; for(i = 0; i < m; i++) Ws[i] = 0; for(i = 0; i < n; i++) Ws[x[i] = r[i]]++; for(i = 1; i < m; i++) Ws[i] += Ws[i - 1]; for(i = n - 1; i >= 0; i--) sa[--Ws[x[i]]] = i; for(j = 1, p = 1; p < n; j <<= 1, m = p) { for(p = 0, i = n - j; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j; for(i = 0; i < n; i++) wv[i] = x[y[i]]; for(i = 0; i < m; i++) Ws[i] = 0; for(i = 0; i < n; i++) Ws[wv[i]]++; for(i = 1; i < m; i++) Ws[i] += Ws[i - 1]; for(i = n - 1; i >= 0; i--) sa[--Ws[wv[i]]] = y[i]; for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++; } return; } int rank[maxn], height[maxn]; void calheight(int *r, int *sa, int n) { int i, j, k = 0; for(i = 1; i <= n; i++) rank[sa[i]] = i; for(i = 0; i < n; height[rank[i++]] = k) for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++); return; } int dp[maxn][20]; void initRMQ(int n) { for(int i = 1; i <= n; i++) dp[i][0] = height[i]; for(int j = 1; (1 << j) <= n; j++) for(int i = 1; i + (1 << j) - 1 <= n; i++) dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); return; } int askRMQ(int a, int b) { //int ra = rank[a], rb = rank[b]; int ra = a, rb = b; if(ra > rb) swap(ra, rb); int k = 0; while((1 << (k + 1)) <= rb - ra + 1) k++; return min(dp[ra][k], dp[rb - (1 << k) + 1][k]); } char A[maxn], B[maxn]; char tmp[maxn << 1]; int R[maxn << 1]; int s[maxn], sa[maxn]; int d; set <ulint> S; vector <pair<int, int> > pal; map<ulint, lint> Ma, Mb; lint calCnt(int l, int r, int n) { int rl = rank[l]; int L = rl + 1, R = n, mid; lint lmost = rl, rmost = rl; while(L <= R) { mid = (L + R) >> 1; if(askRMQ(rl + 1, mid) >= (r - l + 1)) { rmost = mid; L = mid + 1; } else R = mid - 1; } L = 1, R = rl - 1; while(L <= R) { mid = (L + R) >> 1; if(askRMQ(mid + 1, rl) >= (r - l + 1)) { lmost = mid; R = mid - 1; } else L = mid + 1; } return rmost - lmost + 1; } void Manacher(char *s, int *R, int n) { int mx = 0, p = 0; R[0] = 1; S.clear(), pal.clear(); for(int i = 1; i < n; i++) { if(mx > i) R[i] = min(R[2*p - i], mx - i); else R[i] = 1; while(s[i - R[i]] == s[i + R[i]]) R[i]++; if(i + R[i] > mx) { for(int j = mx; j < i + R[i]; j++) { int l = 2*i - j, r = j; l >>= 1; if(r & 1) r >>= 1; else r = (r >> 1) - 1; if(l > r) continue; ulint ans = askHash(l, r); set<ulint> :: iterator it = S.find(ans); if(it == S.end()) { S.insert(ans); pal.push_back(make_pair(l, r)); } } mx = i + R[i], p = i; } } return; } int main() { xp[0] = 1uLL; for(int i = 1; i < maxn; i++) xp[i] = xp[i - 1]*seed; while(scanf("%d", &d) != EOF) { scanf("%s", A); scanf("%s", B); int la = strlen(A), lb = strlen(B); for(int i = 0; i < la; i++) tmp[2*i + 1] = A[i], tmp[2*i + 2] = '#', s[i] = A[i] - 'a' + 1; tmp[0] = '@', tmp[2*la] = '$'; s[la] = 0; initHash(A, la); Manacher(tmp, R, 2*la); da(s, sa, la + 1, 28); calheight(s, sa, la); initRMQ(la); Ma.clear(); for(int i = pal.size() - 1; i >= 0; i--) { if(pal[i].second - pal[i].first + 1 < d) continue; ulint value = askHash(pal[i].first, pal[i].second); Ma[value] = calCnt(pal[i].first, pal[i].second, la); } for(int i = 0; i < lb; i++) tmp[2*i + 1] = B[i], tmp[2*i + 2] = '#', s[i] = B[i] - 'a' + 1; tmp[0] = '@', tmp[2*lb] = '$'; s[lb] = 0; initHash(B, lb); Manacher(tmp, R, 2*lb); da(s, sa, lb + 1, 28); calheight(s, sa, lb); initRMQ(lb); Mb.clear(); for(int i = pal.size() - 1; i >= 0; i--) { if(pal[i].second - pal[i].first + 1 < d) continue; ulint value = askHash(pal[i].first, pal[i].second); Mb[value] = calCnt(pal[i].first, pal[i].second, lb); } lint ans = 0; for(map<ulint, lint> :: iterator it = Ma.begin(); it != Ma.end(); it++) if(Mb[(*it).first] != 0) ans += (*it).second*Mb[(*it).first]; printf("%lld\n", ans);//第一次上UESTC交题...就写%I64d WA了一次... } return 0; }