bzoj3160(manacher,FFT)

Description
这里写图片描述
这里写图片描述
Input
这里写图片描述
Input
这里写图片描述
Sourse
2013湖北互测week1


题意大概是求不连续回文子序列的个数
ans= a n s = 回文子序列个数-回文子串个数
后者显然跑一边manacher的事情
前面这部分怎么处理?
我们令 fi f i 表示倍长(加’#’)后 i i 这位左右对应相等的字符
那以i为中心的对称子序列共有 2fi1 2 f i − 1
问题变成了 fi f i 怎么求

大力推一波式子
fi=i1j=1[s[j]==s[2ij]] f i = ∑ j = 1 i − 1 [ s [ j ] == s [ 2 ∗ i − j ] ]
这个式子已经可以 FFT F F T
为了更加直观,我们把后面的部分放到原串中
fi=i1j=1[s[j]==s[ij]] f i = ∑ j = 1 i − 1 [ s [ j ] == s [ i − j ] ]
后面这部分我们只要分别令串中a的位置为1,b为0 和b为1,a为0直接跑FFT即可
a为1的情况跑出来就是a对 fi f i 的贡献

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define Comp complex<double>
#ifdef M_pi
const double pi = M_pi;
#else
const double pi = acos(-1.0);
#endif
const int q = 1e9+7;
Comp t[401000];
int f[401000] , r[401000];
int mi[401000];
int p[401000];
char s[201000];
ll ans;
int n , flen , N;
void dft(Comp *a ,int f){
    for(int i = 0; i < flen; ++i)
        if(i < r[i]) swap(a[i], a[r[i]]);
    for(int len = 2;len <= flen;len *= 2){
        Comp wn = Comp( cos(2 * pi / len) , f * sin(2 * pi / len));
        for(int k = 0;k <= flen / len - 1;++k){
            int st = k * len;
            Comp w = 1;
            for(int i = 0;i < len / 2;++i){
                Comp x = a[st + i],
                    y = a[st + i + len / 2] * w;
                a[st + i] = x + y;
                a[st + i + len / 2] = x - y;
                w *= wn;
            }
        }
    } 
    if(f == -1) rep(i,0,flen-1) a[i] = (a[i].real()/flen+0.5);
    return;
}       
void solve()
{
    flen = 1;
    while(flen < 2*(n-1)+1) flen*=2;
    int l = log2(flen);
    for(int i = 0;i < flen;++i){
        r[i] = r[i>>1]>>1;
        if(i & 1) r[i] |= 1<<(l-1);
    }
    rep(i,n,flen) t[i] = 0;
    dft(t,1);
    rep(i,0,flen-1) t[i] = t[i]*t[i];
    dft(t,-1);
    rep(i,0,flen-1) f[i+2] = (int)(f[i+2]+t[i].real())%q;
    return;
}
void manacher()
{
    int pos = 0,mx = 0;
    rep(i,1,2*n)
    {
        p[i]=i<mx?min(p[pos*2-i],mx-i):1;
        while(s[i-p[i]] == s[i+p[i]]) p[i]++;
        if(i + p[i] > mx) mx = i + p[i],pos = i;
    }
}
int main()
{
    n++;
    while(scanf("%c",&s[2*n]) != EOF && (s[2*n] == 'a'|| s[2*n] == 'b')) s[2*n-1] = '#',n++;n--;
    s[2*n+1] = '!';s[0] = '?';
    rep(i,0,n-1) if(s[2*i+2] == 'a') t[i] = 1;
    solve();
    rep(i,0,n-1) if(s[2*i+2] == 'b') t[i] = 1;
    else t[i] = 0;
    solve();
    mi[0] = 1;
    rep(i,1,n) mi[i] = (mi[i-1]<<1)%q;
    rep(i,1,2*n) f[i] = (f[i]+1)/2;
    rep(i,1,2*n) if(f[i] > 0)ans = (ans + mi[f[i]] - 1)%q;
    manacher();
    for(int i=2;i<=2*n;i+=2) if(p[i]%2==0) p[i]--;
    for(int i=1;i<=2*n;i+=2) if(p[i]%2==1) p[i]--;
    rep(i,1,2*n) ans = (ans-(p[i]+1)/2+q)%q;
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值