牛客國慶集訓派對Day5 H
阿新 • • 發佈:2018-12-13
題目描述
終於活成了自己討厭的樣子。
天空仍燦爛,它愛著大海。
你喜歡大海,我愛過你。
世界上充滿了巧合。我們把每句話當成一個字串,我們定義a對b的巧合值為a的最長字尾的長度並且它是恰好是b的字首,這裡的字尾或者字首包括字串的本身。 比如字串“天空仍燦爛她喜歡大海”對“她喜歡大海我不愛她了我愛的只是與她初見時蔚藍的天空”的巧合值為5,而字串“她喜歡大海我不愛她了我愛的只是與她初見時蔚藍的天空”對“天空仍燦爛她喜歡大海”的巧合值為2。 現在給出n個字串由"ab"構成的字串s1,s2,...,sn,求出對於所有1≤ i,j≤ n,si對sj的巧合值的和。
輸入描述:
第一行一個整數T(T≤ 1000),表示資料組數。 每組資料第一行一個正整數n(1≤ n≤ 1e5)。接下來n行每行一個字串si,保證字串由"ab"構成。 保證單組資料有,保證所有資料有。
輸出描述:
對於每組資料,輸出一個整數,表示答案。
題解:
把所有字首的hash存在map裡面,只要對於每個字尾找到能和他匹配的個數即可。
然後會出現重複的問題,因為只是匹配最大的字尾和字首。
重複的情況是某一個字尾完全包含另一個字尾,我們只要把串反向後用Kmp求出迴圈節,就知道當前下標為i的字尾包含了哪個字尾。
那麼我們算答案的時候對於當前字尾 只要加上 出現次數 * (長度 - 迴圈節長度)即可。
卡了一下模1e9 + 7,改成ull自然溢位就過了。
程式碼:
#include <bits/stdc++.h> #ifdef LOCAL #define debug(x) cout<<#x<<" = "<<(x)<<endl; #else #define debug(x) 1; #endif #define chmax(x,y) x=max(x,y) #define chmin(x,y) x=min(x,y) #define lson id<<1,l,mid #define rson id<<1|1,mid+1,r #define lowbit(x) x&-x #define mp make_pair #define pb push_back #define fir first #define sec second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const int MOD = 1e9 + 7; const double PI = acos (-1.); const double eps = 1e-10; const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3f; const int MAXN = 2e6 + 5; char s[MAXN]; char *p[MAXN]; int len[MAXN]; #define seed 233 unordered_map<ull, int> q; ull kpw[MAXN]; ull hs[MAXN]; int f[MAXN]; void getFail(char *P, int m) { f[0] = f[1] = 0; for (int i = 1; i < m; i++) { int j = f[i]; while (j && P[i] != P[j]) j = f[j]; f[i + 1] = (P[i] == P[j]) ? j + 1 : 0; } } ll getHash(int l, int r) { return hs[r] - hs[l - 1] * kpw[r - l + 1]; } char t[MAXN]; ll query(char * s, int n) { memcpy(t, s, n); reverse(t, t + n); getFail(t, n); for (int i = 0; s[i]; i++) hs[i + 1] = hs[i] * seed + s[i] - 'a' + 1; ll ret = 0; for (int i = 0; i < n; i++) { ll val = getHash(i + 1, n); int num = q[val]; ret += (ll) num * (n - i - f[n - i]); } return ret; } void init() { kpw[0] = 1; for (int i = 1; i < MAXN; i++) kpw[i] = kpw[i - 1] * seed; } int main() { #ifdef LOCAL freopen ("input.txt", "r", stdin); #endif int T; cin >> T; init(); while(T--) { int n; q.clear(); scanf("%d", &n); int tot = 0; for (int i = 1; i <= n; i++) { scanf("%s", s + tot); p[i] = s + tot; tot += (len[i] = strlen(s + tot)) + 1; for (int j = 0; j < len[i]; j++) { hs[j + 1] = hs[j] * seed + (*(p[i]+j) - 'a') + 1; q[hs[j + 1]]++; } } ll ans = 0; for (int i = 1; i <= n; i++) { ans += query(p[i], len[i]); } printf("%lld\n", ans); } return 0; }