zoukankan      html  css  js  c++  java
  • 题解 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(){;}
    
    呐,这份感情,什么时候可以传达呢
  • 相关阅读:
    使用knockout.js 完毕template binding
    站点建设价格为什么有高有低?站点建设该怎样选择?
    同余 模算术 中国剩余定理
    linux 命令之 apt-get
    [Leetcode]-Reverse Integer
    《Python入门》Windows 7下Python Web开发环境搭建笔记
    javascript之Ajax起步
    SQL server 2012 安装SQL2012出现报错: 启用 Windows 功能 NetFx3 时出错
    C# 反射具体解释
    java8_api_jni
  • 原文地址:https://www.cnblogs.com/Ame-sora/p/14418296.html
Copyright © 2011-2022 走看看