题解 P3181 [HAOI2016]找相同字符 发表于 2019-05-30 | 更新于 2019-06-01 | 分类于 题解 | 阅读次数: 题面 直接对两个串建广义sam然后分别搞出A,B的right集合大小然后乘起来再求和就可以了 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#include <bits/stdc++.h>using namespace std;int buc[800010], a[800010];namespace sam { int son[800010][26], par[800010], cnt, last, len[800010], sze[800010][2]; inline void clear() { cnt = last = 1; } inline void add(int x) { int p = last; int np = last = ++cnt; len[np] = len[p] + 1; for(; p && son[p][x] == 0; p = par[p]) son[p][x] = np; if(p == 0) par[np] = 1; else { int q = son[p][x]; if(len[q] == len[p] + 1) par[np] = q; else { int nq = ++cnt; par[nq] = par[q]; memcpy(son[nq], son[q], sizeof(int[26])); len[nq] = len[p] + 1; par[np] = par[q] = nq; for(; son[p][x] == q; p = par[p]) son[p][x] = nq; } } } inline void get(char *s, int len, int id) { for(int i = 0, now = 1; i < len; i++) sze[now = son[now][s[i] - 'a']][id] = 1; } inline long long calc() { for(int i = 1; i <= cnt; i++) buc[len[i]] ++; for(int i = 1; i <= cnt; i++) buc[i] += buc[i - 1]; for(int i = 1; i <= cnt; i++) a[buc[len[i]]--] = i; for(int i = cnt; i > 0; i--) { sze[par[a[i]]][0] += sze[a[i]][0]; sze[par[a[i]]][1] += sze[a[i]][1]; } long long ans = 0; for(int i = 1; i <= cnt; i++) ans += 1ll * sze[i][0] * sze[i][1] * (len[i] - len[par[i]]); return ans; }};using namespace sam;char A[200010], B[200010];int main() { clear(); int lena, lenb; scanf("%s%s", A, B); lena = strlen(A), lenb = strlen(B); for(int i = 0; i < lena; i++) add(A[i] - 'a'); last = 1; for(int i = 0; i < lenb; i++) add(B[i] - 'a'); get(A, lena, 0); get(B, lenb, 1); return cout << calc() << endl, 0;}