[ZJOI2019]开关

一、题目

点此看题

二、解法

考虑每个灯的生成函数,那么答案的生成函数为它们的乘积,设 P = ∑ p i P=\sum p_i P=pi(这里用 e e e不是特别严谨,因为本题不需要指数型生成函数,但是为了方便表示无穷级数,使用 e e e可能会更加简洁):
F ( x ) = ∏ i = 1 n e p i P x + ( − 1 ) s i e − p i P x 2 F(x)=\prod_{i=1}^n \frac{e^{\frac{p_i}{P}x}+(-1)^{s_i}e^{-\frac{p_i}{P}x}}{2} F(x)=i=1n2ePpix+(1)siePpix但是还有一个问题,就是上面的生成函数并不会在第一次满足条件是就停止,我们考虑转满一圈,也就是操作会原状态的生成函数:
G ( x ) = ∏ i = 1 n e p i P x + e − p i P x 2 G(x)=\prod_{i=1}^n \frac{e^{\frac{p_i}{P}x}+e^{-\frac{p_i}{P}x}}{2} G(x)=i=1n2ePpix+ePpix求出 F , G F,G F,G直接暴力背包,时间复杂度 O ( n p ) O(np) O(np),考虑答案的生成函数为 H ( x ) H(x) H(x),则满足 h ( x ) g ( x ) = f ( x ) h(x)g(x)=f(x) h(x)g(x)=f(x) h , g , f h,g,f h,g,f H , G , F H,G,F H,G,F的普通生成函数),考虑使用闭形式来表示它们之间的转化,它们之间满足这样的转化关系:
f ( x ) = ∑ i = − P P a i 1 − i P x f(x)=\sum_{i=-P}^{P} \frac{a_i}{1-\frac{i}{P}x} f(x)=i=PP1Pixai此时要求的答案是 h ′ ( 1 ) h'(1) h(1),求导就是把每种概率乘上他的权值(步数),算出来就是期望,可以使用这个公式,( 1 g ( x ) \frac{1}{g(x)} g(x)1的求导可以当做复合函数求导,也就是加入一个辅助函数 f ( x ) = 1 x f(x)=\frac{1}{x} f(x)=x1):
( f ( x ) g ( x ) ) ′ = ( f ( x ) g ( x ) − 1 ) ′ = f ′ ( x ) g ( x ) − f ( x ) g ′ ( x ) g ( x ) 2 (\frac{f(x)}{g(x)})'=(f(x)g(x)^{-1})'=\frac{f'(x)g(x)-f(x)g'(x)}{g(x)^2} (g(x)f(x))=(f(x)g(x)1)=g(x)2f(x)g(x)f(x)g(x)发现这样算出来的 h h h是不收敛的,我们把 f , g f,g f,g同乘 ∏ 1 − i p \prod1-\frac{i}p{} 1pi,现在的问题在于解决 f ( x ) f(x) f(x)的导数,我们来推式子:
f ( x ) = ∑ a i ∏ j ≠ i 1 − j p x f(x)=\sum a_i\prod_{j\not=i}1-\frac{j}{p}x f(x)=aij=i1pjx为了方便表示,我们设 g i ( x ) = a i ∏ j ≠ i j p x , h i ( x ) = 1 − i p x g_i(x)=a_i\prod_{j\not=i}\frac{j}{p}x,h_i(x)=1-\frac{i}p{x} gi(x)=aij=ipjx,hi(x)=1pix,我们想对 g g g求导:
g i ′ ( x ) = a i ∏ j ≠ i h j ( x ) ′ g_i'(x)=a_i\prod_{j\not=i}h_j(x)' gi(x)=aij=ihj(x) g i ′ ( x ) = a i ∑ k ≠ i ( ∏ j ≠ i , j ≠ k h j ( x ) ) × h k ( x ) ′ g_i'(x)=a_i\sum_{k\not=i}(\prod_{j\not=i,j\not=k}h_j(x))\times h_k(x)' gi(x)=aik=i(j=i,j=khj(x))×hk(x) g i ′ ( x ) = a i ∑ k ≠ i ( ∏ j ≠ i h j ( x ) ) × h k ( x ) ′ h k ( x ) . . . . . . ∗ g_i'(x)=a_i\sum_{k\not=i}(\prod_{j\not=i}h_j(x))\times \frac{h_k(x)'}{h_k(x)}......* gi(x)=aik=i(j=ihj(x))×hk(x)hk(x)...... g i ′ ( x ) = a i ( ∏ j ≠ i h j ( x ) ) ∑ k ≠ i h k ( x ) ′ h k ( x ) g_i'(x)=a_i(\prod_{j\not=i}h_j(x))\sum_{k\not=i}\frac{h_k(x)'}{h_k(x)} gi(x)=ai(j=ihj(x))k=ihk(x)hk(x) g i ′ ( x ) = a i ( ∏ j ≠ i 1 − j p x ) ∑ k ≠ i − k p 1 − k p x g_i'(x)=a_i(\prod_{j\not=i}1-\frac{j}{p}x)\sum_{k\not=i}\frac{-\frac{k}{p}}{1-\frac{k}{p}x} gi(x)=ai(j=i1pjx)k=i1pkxpk那么 f ′ ( x ) f'(x) f(x)就算出来了,长成这样:
f ′ ( x ) = ∑ i a i ( ∏ j ≠ i 1 − j p x ) ∑ k ≠ i − k p 1 − k p x f'(x)=\sum_ia_i(\prod_{j\not=i}1-\frac{j}{p}x)\sum_{k\not=i}\frac{-\frac{k}{p}}{1-\frac{k}{p}x} f(x)=iai(j=i1pjx)k=i1pkxpk考虑求除 f ′ ( 1 ) f'(1) f(1)的值,可以分类讨论,由于 x = 1 x=1 x=1是, 1 − i p 1-\frac{i}{p} 1pi很特殊,我们考虑 i i i是否等于 p p p

  • i ≠ p i\not=p i=p,考虑到 j j j的枚举中会有 0 0 0这一项产生( j = p j=p j=p时),那就都消完了?等等,看我标注了*号的柿子,我们为了提出相同的一项而乘上又除去了 1 − k p x 1-\frac{k}p{x} 1pkx,所以在 k k k中产生的 − 1 0 \frac{-1}{0} 01必须要与 0 0 0的一项对消,产生 − 1 -1 1,所以当 i ≠ p i\not=p i=p时, k k k只能等于 p p p,这样我们就可以对 g g g函数进行化简:
    g i ′ ( x ) = − a i ∏ j ≠ i , j ≠ p 1 − j p x g_i'(x)=-a_i\prod_{j\not=i,j\not=p}1-\frac{j}p{x} gi(x)=aij=i,j=p1pjx g i ′ ( x ) = − ∏ j ≠ p 1 − j p x × a i 1 − i p x g_i'(x)=-\prod_{j\not=p}1-\frac{j}{p}x\times\frac{a_i}{1-\frac{i}{p}x} gi(x)=j=p1pjx×1pixai
  • i = p i=p i=p,直接带推出的 f ′ ( x ) f'(x) f(x)的柿子去算,比较简单。

分类讨论之后,我们可以知道 f ′ ( 1 ) f'(1) f(1)的值:
f ′ ( 1 ) = − ( ∏ i ≠ p 1 − i p ) ( ∑ i ≠ p a i 1 − i p + a p ∑ i ≠ p i p 1 − i p ) f'(1)=-(\prod_{i\not=p}1-\frac{i}{p})(\sum_{i\not=p}\frac{a_i}{1-\frac{i}{p}}+a_p\sum_{i\not=p}\frac{\frac{i}{p}}{1-\frac{i}{p}}) f(1)=(i=p1pi)(i=p1piai+api=p1pipi)知道了 f ′ ( 1 ) f'(1) f(1)的求导之后, g ′ ( 1 ) g'(1) g(1)也很容易(好像和推导的重名了,写到这里才发现,请谅解),我们可以带入上面对分式求导的柿子,就可以算出答案(设 a i a_i ai f f f的系数, b i b_i bi g g g的系数,容易发现 a p = b p = 1 2 n a_p=b_p=\frac{1}{2^n} ap=bp=2n1):
2 n ∑ i ≠ p b i − a i 1 − i p 2^n\sum_{i\not=p}\frac{b_i-a_i}{1-\frac{i}{p}} 2ni=p1pibiai写的我要吐了,贴上简洁的代码:

#include <cstdio>
#include <cstring>
#define int long long
const int M = 50005;
const int MOD = 998244353;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,sum,inv,ans,s[105],tmp[2*M],f[2*M],g[2*M];
int qkpow(int a,int b)
{
    int r=1;
    while(b>0)
    {
        if(b&1) r=r*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return r;
}
signed main()
{
    n=read();
    for(int i=1; i<=n; i++)
        s[i]=read();
    inv=qkpow(2,MOD-2);
    f[M]=g[M]=1;
    for(int i=1; i<=n; i++)
    {
        int x=read();
        sum+=x;
        memset(tmp,0,sizeof tmp);
        for(int j=-sum; j+x<=sum; j++) tmp[j+x+M]=(tmp[j+x+M]+inv*f[j+M])%MOD;
        for(int j=-sum+x; j<=sum; j++) tmp[j-x+M]=(tmp[j-x+M]+(s[i]?MOD-inv:inv)*f[j+M])%MOD;
        memcpy(f,tmp,sizeof tmp);
        //
        memset(tmp,0,sizeof tmp);
        for(int j=-sum; j+x<=sum; j++) tmp[j+x+M]=(tmp[j+x+M]+inv*g[j+M])%MOD;
        for(int j=-sum+x; j<=sum; j++) tmp[j-x+M]=(tmp[j-x+M]+inv*g[j+M])%MOD;
        memcpy(g,tmp,sizeof tmp);
    }
    for(int i=-sum; i<=sum; i++) ans=(ans+(g[i+M]-f[i+M]+MOD)*qkpow(sum-i,MOD-2))%MOD;
    printf("%lld\n",ans*sum%MOD*qkpow(2,n)%MOD);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值