• [AGC058D]Yet Another ABC String


    Yet Another ABC String

    题解

    首先看到这个题,一个方向是去考虑容斥。
    可以发现,如果有连续不合法部分的话,可以发现,他一定是一段连续的 . . . A B C A B C A B C A B C . . . ...ABCABCABCABC... ...ABCABCABCABC...
    这是一个非常好的性质,因为如果我们之间容斥不合法位置的起点集合的话是非常麻烦的,这可以让我们得到一个非常好的转化。
    每次强制原串中的一些部分呈现我们上面所说的这样的连续段,容斥我们这些连续段的集合。

    考虑选择一个这样长度为 n n n的段,它所贡献容斥系数。
    手推一下前几项可以发现,容斥系数在模 3 3 3 0 0 0的位置上为 − 1 -1 1,在模 3 3 3 1 1 1的位置上为 1 1 1,模 3 3 3 2 2 2的位置上为 0 0 0
    证明大概可以考虑通过递推式归纳证明,不是很会证明。(先留个坑)
    好的,既然知道这东西了,我们也就很容易设计出来一个 d p dp dp转移。
    由于有效的要么是模 3 3 3 0 0 0,要么模 3 3 3 1 1 1,相当于要么让所有数都减去同样的个数,要么在这基础上挑一个数多减一次。
    定义 d p i , j dp_{i,j} dpi,j表示在构造一个长度为 i i i的串,让每个数减去 i − j 3 \frac{i-j}{3} 3ij,并且,进行 j j j次挑一个数多减 1 1 1的操作,得到的总系数和。
    可以得到其转移式:
    d p i , j = d p i − 1 , k − 1 + ∑ k = 1 min ⁡ ( i , 3 j + 1 ) [ k ≡ 1 ( m o d 3 ) ] d p i − k , j − k − 1 3 − 3 [ k ≡ 0 ( m o d 3 ) ] d p i − k , j − k 3 dp_{i,j}=dp_{i-1,k-1}+\sum_{k=1}^{\min(i,3j+1)}[k\equiv 1\pmod{3}]dp_{i-k,j-\frac{k-1}{3}}-3[k\equiv 0\pmod{3}]dp_{i-k,j-\frac{k}{3}} dpi,j=dpi1,k1+k=1min(i,3j+1)[k1(mod3)]dpik,j3k13[k0(mod3)]dpik,j3k其中 d p i − 1 , k − 1 dp_{i-1,k-1} dpi1,k1表示这个位置没被选择容斥, 3 3 3的系数是由于模 3 3 3 0 0 0的情况有 A B C , B C A , C A B ABC,BCA,CAB ABC,BCA,CAB三种结构,模 3 3 3 1 1 1的情况结构是固定的,没必要乘 3 3 3
    答案显然可以通过 d p dp dp值算出来,有
    A n s = ∑ ( n − 3 i A − i , B − i , C − i ) d p n , n − i Ans=\sum\binom{n-3i}{A-i,B-i,C-i}dp_{n,n-i} Ans=(Ai,Bi,Cin3i)dpn,ni
    再对上面的式子根据模 3 3 3余数加个前缀和优化,我们就得到一个简单的 O ( n 2 ) O\left(n^2\right) O(n2) d p dp dp做法了。

    接下来让我们来看看怎么优化上面的这个 d p dp dp,不妨考虑生成函数。
    定义二元生成函数 G ( x , y ) G(x,y) G(x,y),其中 [ x i y j ] G [x^iy^j]G [xiyj]G代表 d p i , j dp_{i,j} dpi,j的值。
    通过 G G G的递推式可以得到,
    F = x + ∑ i = 1 ∞ x 3 i + 1 y i − 3 x 3 i y i = x − 3 x 3 y 1 − x 3 y G = ∑ i = 0 ∞ F i = 1 1 − F ( x , y ) = 1 − x 3 y 1 − x + 2 x 3 y F=x+\sum_{i=1}^{\infty}x^{3i+1}y^i-3x^{3i}y^i=\frac{x-3x^3y}{1-x^3y}\\ G=\sum_{i=0}^{\infty} F^i=\frac{1}{1-F(x,y)}=\frac{1-x^3y}{1-x+2x^3y}\\ F=x+i=1x3i+1yi3x3iyi=1x3yx3x3yG=i=0Fi=1F(x,y)1=1x+2x3y1x3y同样,考虑现在答案怎么计算。
    A n s = ∑ i = 0 min ⁡ ( A , B , C ) ( n − 3 i A − i , B − i , C − i ) [ x n y i ] G Ans=\sum_{i=0}^{\min(A,B,C)}\binom{n-3i}{A-i,B-i,C-i}[x^ny^i]G Ans=i=0min(A,B,C)(Ai,Bi,Cin3i)[xnyi]G G ′ = 1 1 − x + 2 x 3 y = ∑ ( x − 2 x 3 y ) i G'=\frac{1}{1-x+2x^3y}=\sum (x-2x^3y)^i G=1x+2x3y1=(x2x3y)i,显然有 [ x n y m ] G = [ x n y m ] G ′ − [ x n − 3 y m − 1 ] G ′ [x^ny^m]G=[x^ny^m]G'-[x^{n-3}y^{m-1}]G' [xnym]G=[xnym]G[xn3ym1]G>
    现在我们就只需要考虑 [ x n y m ] G ′ [x^ny^m]G' [xnym]G怎么算了,这个好搞,可以解方程,看两边分别贡献了多少。
    a − 3 b = n , b = m ⇒ a = n − 3 m a-3b=n,b=m\Rightarrow a=n-3m a3b=n,b=ma=n3m,所以根据二项式定理可得,
    [ x n y m ] G ′ = ( n − 2 m m ) ( − 2 ) m [x^ny^m]G'=\binom{n-2m}{m}(-2)^m [xnym]G=(mn2m)(2)m带到上面的式子里面去就可以快速算出答案了。

    时间复杂度 O ( A + B + C ) O\left(A+B+C\right) O(A+B+C)

    源码

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #include
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    #define MAXN 3000005
    #define pb push_back
    #define mkpr make_pair
    #define fir first
    #define sec second
    const LL INF=0x3f3f3f3f3f3f3f3f;
    const int mo=998244353;
    template<typename _T>
    void read(_T &x){
        _T f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
        x*=f;
    }
    template<typename _T>
    _T Fabs(_T x){return x<0?-x:x;}
    int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
    void Add(int &x,int y,int p){x=add(x,y,p);}
    int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
    int nA,nB,nC,n,fac[MAXN],inv[MAXN],ff[MAXN],pw2[MAXN],ans;
    void init(){
        fac[0]=fac[1]=inv[0]=inv[1]=ff[1]=pw2[0]=1;
        for(int i=2;i<=n;i++)
            fac[i]=1ll*i*fac[i-1]%mo,
            ff[i]=1ll*(mo-mo/i)*ff[mo%i]%mo,
            inv[i]=1ll*ff[i]*inv[i-1]%mo;
        for(int i=1;i<=n;i++)pw2[i]=mo-add(pw2[i-1],pw2[i-1],mo);
    }
    int C(int x,int y){
        if(x<0||y<0||x<y)return 0;
        return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;
    }
    int work(int x,int y){
        if(x<0||y<0||x<y+y)return 0;
        return 1ll*pw2[y]*C(x-y-y,y)%mo;
    }
    signed main(){
        read(nA);read(nB);read(nC);n=nA+nB+nC;init();
        for(int i=0;i<=min(nA,min(nB,nC));i++){
            int tmp=add(work(n,i),mo-work(n-3,i-1),mo);
            Add(ans,1ll*C(n-i*3,nA-i)*C(n-i*2-nA,nB-i)%mo*tmp%mo,mo);
        }
        printf("%d\n",ans);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    谢谢!!!

  • 相关阅读:
    【MATLAB教程案例39】语音信号的PCM编解码matlab仿真学习
    2024.7.31 Spyglass lint tcl 使用总结
    使用枚举实现编译时可变长数组
    ESP8266-Arduino编程实例-MQ-5液化天然气传感器驱动
    adb控制常用命令
    随手记录第十话 -- 升级SpringBoot3.0 + JDK17的踩坑记录
    scratch绘制正方形 电子学会图形化编程scratch等级考试二级真题和答案解析2022年6月
    计算机网络——以太网的信道利用率
    基于Spark的数据清洗与转换
    行者AI解析内容审核平台中的图像检测技术原理
  • 原文地址:https://blog.csdn.net/Tan_tan_tann/article/details/126383405