BZOJ 3160 万径人踪灭

做学长出的题目好开心:-)

提示:
1. 可以尝试去推导答案的公式 , 然后优化处理

详细题解代码后:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <cassert>

using namespace std;

struct complex
{
    double x , y;
    complex(double x=0 , double y=0):x(x),y(y){}

    double real() { return x; }
    double imag() { return y; }
    complex operator +(complex b) { return complex(x + b.x , y + b.y); }
    complex operator -(complex b) { return complex(x - b.x , y - b.y); }
    complex operator *(complex b) { return complex(x * b.x - y * b.y , x * b.y + y * b.x);; }
    complex operator /(double  b) { return complex(x / b , y / b); }
};

typedef complex cd;
typedef vector<cd> vc;
typedef vector<double> vd;

void FFT(vc &a , int inv)
{
    int n = a.size();
    for(int i=0,j=0;i<n;i++)
    {
        if(j > i) swap(a[i] , a[j]);

        int k = n;
        while(j & (k >>= 1)) j &= ~k;
        j |= k;
    }

    double Pi = inv * acos(-1);
    for(int i=1;i<n;i <<= 1)
    {
        cd wn = cd(cos(Pi/i) , sin(Pi/i));
        for(int j=0;j<n;j += i<<1)
        {
            cd w = cd(1 , 0);
            for(int k=j;k<i+j;k++)
            {
                cd x = a[k];
                cd y = a[k+i] * w;
                a[k] = x + y;
                a[k+i]=x - y;
                w = w*wn;
            }
        }
    }

    if(inv == -1) for(int i=0;i<n;i++) a[i] = a[i] / n;
}

vd operator *(vd a , vd b)
{
    int s1 = a.size() , s2 = b.size() , s = 2;
    while(s <= s1 + s2) s <<= 1;

    vc c(s , 0) , d(s , 0);
    for(int i=0;i<s1;i++) c[i] = a[i];
    FFT(c , 1);
    for(int i=0;i<s2;i++) d[i] = b[i];
    FFT(d , 1);
    for(int i=0;i<s;i++)  c[i] = c[i] * d[i];
    FFT(c ,-1);

    vd res(s1+s2-1 , 0);
    for(int i=0;i<s1+s2-1;i++) res[i] = c[i].real();
    return res;
}

const int maxn = 1e5+1e2;
const int modu = 1e9+7;

int n;
char s[maxn] , s1[maxn*2]; int p[maxn*2];
int manacher()
{
    int res = 0 , cnt = 0;
    s1[cnt++] = 'c'; s1[cnt++] = 'd';
    for(int i=0;i<n;i++) s1[cnt++] = s[i] , s1[cnt++] = 'd';

    int mx = 0 , id = 0;
    for(int i=1;i<cnt;i++)
    {
        p[i] = mx > i ? min(mx - i, p[2*id - i]) : 1;
        while(s1[i + p[i]] == s1[i - p[i]]) p[i]++;
        (res += p[i]/2) %= modu;

        if(i + p[i] > mx) mx = i + p[id = i];
    }

    return res;
}

int bits[maxn]={1};

int main(int argc, char *argv[]) {

    scanf("%s" , s);

    n = strlen(s);
    vd a(n , 0) , b(n , 0);
    for(int i=1;i<=n;i++) bits[i] = (bits[i-1]<<1) % modu;
    for(int i=0;i<n;i++) if(s[i] == 'a') a[i] = 1; else b[i] = 1;

    a = a*a;
    b = b*b;

    int res = 0;
    for(int i=0;i<a.size();i++) (res += bits[(int(a[i]+0.5) + int(b[i]+0.5) + 1)/2]-1) %= modu;
    cout<< (res + modu - manacher())%modu <<endl;

    return 0;
}

下述中 S 表示原串

Fi=js[ij]==s[i+j]
Answer=(i2Fi1)

其中回文串的数量不难用 manacher 算法求出 , 而重点在于求 Fi

观察 Fi 的表达式 ,这就是个卷积形式啊!
Ai=(si== a ) , 不难证明 A×A 中的每一项都是a 对某一项 Fj 的贡献。 b 同理可得。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值