在纸上画了画感受一下可以感觉和循环节有关, 我们把每个可以表示的串写成 pre_a_i + pre_b_j的形式,
我们使得每个串在 i 最大的时候被统计到, 那么我们考虑答案为n * m - 重复的串个数,
对于pre_a_i + pre_b_j 这个串, 我们记b[0] - b[ j ] 的循环节是k, 它被重复算了当且仅当,
对于a[ 0 ] - a[ i ] 这个串存在一个长度为k的后缀和循环节相同。
那么我们枚举pre_a_i, 记L为a[ i + 1 ] 开始的串与b串的lcp, cnt[ i ] 为b的前缀中循环节小于等于 i 的个数,
那么对于当前的pre_a_i多算的个数为cnt[L], 减掉就好了。
#include<bits/stdc++.h> #define LL long long #define ull unsigned long long using namespace std; const int N = (int)1e5 + 7; int n, m; char s[N], t[N]; int cnt[N]; int f[N]; vector<int> Zalgo(string &s) { vector<int> v(1, s.size()); for(int i = 1, l = -1, r = -1; i < s.size(); i++) { if(i <= r && v[i - l] < r - i + 1) v.push_back(v[i - l]); else { l = i; r = (i > r) ? i : (r + 1); while(r < s.size() && s[r - i] == s[r]) r++; v.push_back((r--) - l); } } v.push_back(0); return v; } void getNext(char *s, int n) { f[0] = 0; f[1] = 0; for(int i = 1; i < n; i++) { int j = f[i]; while(j && s[i] != s[j]) j = f[j]; f[i + 1] = (s[i] == s[j] ? j + 1 : 0); } for(int i = 2; i <= n; i++) { if(f[i] > 0) cnt[i - f[i]]++; } } int main() { scanf("%s%s", s + 1, t + 1); n = strlen(s + 1); m = strlen(t + 1); getNext(t + 1, m); for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1]; string S; for(int i = 1; i <= m; i++) S.push_back(t[i]); S.push_back('$'); for(int i = 1; i <= n; i++) S.push_back(s[i]); vector<int> lcp = Zalgo(S); LL ans = 1LL * n * m; for(int i = 2; i <= n; i++) { ans -= cnt[lcp[i + m]]; } printf("%lld ", ans); return 0; } /* */