Luogu4199 万径人踪灭 FFT、Manacher

传送门


先不考虑”不是连续的一段“这一个约束条件。可以知道:第$i$位与第$j$位相同,可以对第$\frac{i+j}{2}$位置上产生$1$的贡献(如果$i+j$为奇数表明它会对一条缝产生$1$的贡献),而每一个位置上或缝上的满足条件的字符串的个数就是$2^\text{贡献}-1$。把$\frac{1}{2}$忽略掉,也就是说:第$i$位与第$j$位相同时会在第$i+j$位产生$1$的贡献。这个是经典的生成函数+$FFT$求解的问题。具体来说,将$a,b$两个字母分开计算,以计算$a$的贡献为例,如果第$i$位上为$a$,则两个多项式的$x^i$项的系数为$1$,否则为$0$,然后将两个多项式做卷积得到的结果的每一项的系数就是$a$字母对每一位做的贡献,$b$同理。

然后我们考虑减掉连续的一段。连续的一段就是一段回文串,使用$Manacher$求解即可。

#include<bits/stdc++.h>
#define ld long double
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    bool f = 0;
    char c = getchar();
    while(c != EOF && !isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(c != EOF && isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 280010 , MOD = 1e9 + 7;
char s[MAXN >> 1] , news[MAXN];
struct comp{
    ld x , y;

    comp(ld _x = 0 , ld _y = 0){
        x = _x;
        y = _y;
    }

    comp operator +(comp a){
        return comp(x + a.x , y + a.y);
    }

    comp operator -(comp a){
        return comp(x - a.x , y - a.y);
    }

    comp operator *(comp a){
        return comp(x * a.x - y * a.y , x * a.y + y * a.x);
    }
}A[MAXN];
int need , dir[MAXN] , calc[MAXN] , manacher[MAXN];
const ld pi = acos(-1);

inline int poww(long long a , int b){
    int times = 1;
    while(b){
        if(b & 1)
            times = times * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return times;
}

inline void swap(comp& a , comp& b){
    comp t = a;
    a = b;
    b = t;
}

inline void FFT(int type){
    comp wn , w;
    for(int i = 1 ; i < need ; ++i)
        if(i < dir[i])
            swap(A[i] , A[dir[i]]);
    for(int i = 1 ; i < need ; i <<= 1){
        wn = comp(cos(pi / i) , type * sin(pi / i));
        for(int j = 0 ; j < need ; j += i << 1){
            w = comp(1 , 0);
            for(int k = 0 ; k < i ; ++k , w = w * wn){
                comp x = A[j + k] , y = A[i + j + k] * w;
                A[j + k] = x + y;
                A[i + j + k] = x - y;
            }
        }
    }
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("4199.in" , "r" , stdin);
    //freopen("4199.out" , "w" , stdout);
#endif
    scanf("%s" , s);
    int l = strlen(s) , sum = 0;
    need = 1;
    while(need < l << 1)
        need <<= 1;
    for(int i = 1 ; i < need ; ++i)
        dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0);
    
    for(int i = 0 ; i < l ; ++i)
        if(s[i] == 'a')
            A[i].x = 1;
    FFT(1);
    for(int i = 0 ; i < need ; ++i)
        A[i] = A[i] * A[i];
    FFT(-1);
    for(int i = 0 ; i < need ; ++i)
        calc[i] = A[i].x / need / 2 + 0.6;

    memset(&A , 0 , sizeof(A));
    for(int i = 0 ; i < l ; ++i)
        if(s[i] == 'b')
            A[i].x = 1;
    FFT(1);
    for(int i = 0 ; i < need ; ++i)
        A[i] = A[i] * A[i];
    FFT(-1);
    for(int i = 0 ; i < need ; ++i){
        calc[i] += A[i].x / need / 2 + 0.6;
        sum = (sum + poww(2 , calc[i]) - 1) % MOD;
    }

    for(int i = 0 ; i < l ; ++i)
        news[(i << 1) + 1] = s[i];
    int maxD = 0 , maxI = 0;
    for(int i = 1 ; i < l << 1 ; ++i){
        if(maxD > i)
            manacher[i] = min(manacher[maxI * 2 - i] , maxD - i - 1);
        while(i - manacher[i] >= 0 && i + manacher[i] <= l << 1 && news[i - manacher[i]] == news[i + manacher[i]])
            ++manacher[i];
        sum = (sum - (manacher[i] >> 1) + MOD) % MOD;
        if(i + manacher[i] > maxD){
            maxD = i + manacher[i];
            maxI = i;
        }
    }
    cout << sum;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10052537.html
今日推荐