Codeforces 1090J Two Prefixes

Two Prefixes

在纸上画了画感受一下可以感觉和循环节有关, 我们把每个可以表示的串写成 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
#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\n", ans);
    return 0;
}

/*
*/

 

你可能感兴趣的:(Codeforces 1090J Two Prefixes)