题解 P4199/BZOJ3160【万径人踪灭】

简化题面

给定只含有字符(a)(b)的字符串,求位置关于某根轴对称的不连续回文子序列数量

解题思路

显然答案=总数-不合法的方案数。

本题中不合法的方案数显然为连续的回文子序列,即回文子串。可以使用(mathcal{Manacher})直接来求。

考虑怎么求总数,即位置关于某根轴对称的回文子序列

对于回文子序列的最长长度为(l)的回文子序列,他会含有(lceilfrac l2 ceil)个对称的字符对,我们考虑先求出相同的(a)的字符对的数量,若当前位置为(a)则为(1)构造生成函数,然后自己卷自己即为相同的答案,然后在对(b)做相同的事情就是回文子序列的最长长度。

然后考虑其中含有的(lceilfrac l2 ceil)个字符集可以选或者不选,那么我们可以想到答案为

[sum_{i=0}^{lceilfrac l2 ceil-1}dbinom{lceilfrac l2 ceil}{i} ]

即为(2^{lceilfrac l2 ceil}-1)

最后求出来相减就是答案

(mathcal{Code})

// Author: Ame__
#include<bits/stdc++.h>
#include<stdint.h>
#define _ 0
#define AME__DEBUG
#define bomb exit(0)
#define LOG(FMT...) fprintf(stderr , FMT)
#define TOWA(FMT...) fprintf(stdout , FMT)
using namespace std;
/*Grievous Lady*/
    
typedef int32_t i32;
typedef int64_t i64;
typedef double qwq;
    
const int BUF_SIZE = 1 << 12;
char buf[BUF_SIZE] , *buf_s = buf , *buf_t = buf + 1;
    
#define PTR_NEXT() 
{ 
    buf_s ++; 
    if(buf_s == buf_t) 
    { 
        buf_s = buf; 
        buf_t = buf + fread(buf , 1 , BUF_SIZE , stdin); 
    } 
}
    
#define mians(_s_) 
{ 
    while(!isgraph(*buf_s)) PTR_NEXT();
    char register *_ptr_ = (_s_); 
    while(isgraph(*buf_s) || *buf_s == '-') 
    { 
        *(_ptr_ ++) = *buf_s; 
        PTR_NEXT(); 
    } 
    (*_ptr_) = ''; 
}
    
template <typename _n_> void mian(_n_ & _x_){
    while(*buf_s != '-' && !isdigit(*buf_s)) PTR_NEXT();
    bool register _nega_ = false; if(*buf_s == '-'){ _nega_ = true; PTR_NEXT(); }
    _x_ = 0; while(isdigit(*buf_s)){ _x_ = _x_ * 10 + *buf_s - '0'; PTR_NEXT(); } if(_nega_) _x_ = -_x_;
}
    
const i32 mod = 1e9 + 7;
const i32 kato = 2e6 + 10;
const i32 Mod = 998244353;

template <typename _n_> bool cmax(_n_ &a , const _n_ &b){ return a < b ? a = b , 1 : 0; }
template <typename _n_> bool cmin(_n_ &a , const _n_ &b){ return a > b ? a = b , 1 : 0; }

i32 n , cnt , ans , len = 1;
i32 f[kato] , g[kato] , h[kato] , p[kato] , pia[kato];
char s[kato] , res[kato];

inline i32 quick_pow(i32 a , i32 b){
    i32 res = 1;
    for(; b ; b >>= 1 , a = static_cast<i64>(a) * a % Mod){
        if(b & 1){
            res = static_cast<i64>(res) * a % Mod;
        }
    }
    return res;
}

inline void NTT(i32 *y , i32 len , i32 opt){
    i32 *rev = new int[len];
    rev[0] = 0;
    for(i32 i = 1;i < len;i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (len >> 1));
    for(i32 i = 0;i < len;i ++) if(rev[i] > i) swap(y[rev[i]] , y[i]);
    for(i32 i = 1;i < len;i <<= 1){
        i32 G1 = quick_pow(3 , (Mod - 1) / (i << 1));
        for(i32 j = 0;j < len;j += (i << 1)){
            for(i32 k = 0 , g = 1;k < i;k ++ , g = 1LL * g * G1 % Mod){
                i32 res = static_cast<i64>(y[i + j + k]) * g % Mod;
                y[i + j + k] = ((y[j + k] - res) % Mod + Mod) % Mod;
                y[j + k] = (y[j + k] + res) % Mod;
            }
        }
    }
    if(opt == -1){
        reverse(y + 1 , y + len);
        for(i32 i = 0 , inv = quick_pow(len , Mod - 2);i < len;i ++) y[i] = 1LL * y[i] * inv % Mod;
    }
    delete []rev; rev = 0x0;
}

#define init() 
{ 
    pia[0] = 1 , pia[1] = 2; 
    for(i32 i = 2;i <= len;i ++) 
    { 
        pia[i] = 1LL * pia[i - 1] * 2 % mod; 
    } 
}

inline int Ame_(){
#ifdef AME__
    freopen(".in" , "r" , stdin); freopen(".out" , "w" , stdout); int nol_cl = clock();
#endif
    scanf("%s" , s) , n = strlen(s); res[0] = '#';
    for(i32 i = 0;i < n;i ++) res[++ cnt] = '|' , res[++ cnt] = s[i];
    res[++ cnt] = '|';
    for(i32 l = 1 , r = 0 , mid = 0;l <= cnt;l ++){
        if(l <= r) p[l] = min(p[2 * mid - l] , r - l + 1);
        else p[l] = 1;
        while(res[l - p[l]] == res[l + p[l]]) p[l] ++;
        if(l + p[l] - 1 > r) r = l + p[l] - 1 , mid = l;
    }
    for(i32 i = 1;i <= cnt;i ++) ans = (ans - p[i] / 2 + mod) % mod; 
    for(len = 1 ; len <= 2 * n ; len <<= 1); init();
    for(i32 i = 0;i < n;i ++) if(s[i] == 'a') g[i] = 1;
    NTT(g , len , 1);
    for(i32 i = 0;i < len;i ++) g[i] = static_cast<i64>(g[i]) * g[i] % Mod;
    NTT(g , len , -1);
    for(i32 i = 0;i < n;i ++) if(s[i] == 'b') h[i] = 1;
    NTT(h , len , 1);
    for(i32 i = 0;i < len;i ++) h[i] = static_cast<i64>(h[i]) * h[i] % Mod;
    NTT(h , len , -1);
    for(i32 i = 0;i < len;i ++) f[i] = (g[i] + h[i]) % mod;
    for(i32 i = 0;i < len;i ++) ans = (ans + pia[(f[i] + 1) >> 1] - 1) % mod;
    TOWA("%d
" , ans);
#ifdef AME__TIME
    LOG("Time: %dms
", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
#endif
    return ~~(0^_^0); /*さようならプログラム*/
}
    
int Ame__ = Ame_();
    
int main(){;}
呐,这份感情,什么时候可以传达呢
原文地址:https://www.cnblogs.com/Ame-sora/p/14418296.html