[ZJOI2019]开关

[ZJOI2019]开关 

题解

到了就停止,很麻烦,因为要状压

走了i步,还没有停止方案数,再除以概率,还是不行,还要状压

所以干脆反演(容斥?)直接求i步之后停止的概率,不管之前有没有停止,然后进行反演

 

概率生成函数

1.每个开关的EGF

OGF:j开关的x^i的系数定义为:操作了i次,都操作到了j,并且到达了目标状态的概率

EGF:额外除以i!,为了之后多重集合排列用,可以直接用e代替

2.总共的EGF

直接把每个EGF乘起来

这一步可以背包得到e^(ix)的系数a

3.反演,

要求的生成函数OGF是h,这样h'(1)就是答案

而g*h=f,h=f/g

g就是si=0的状态下的OGF(等价于绕环)

EGF和OGF的转化?就是每一位乘上i!

把e麦克劳林展开,直接乘上i!即可

计算h'(1)要用到f'(1),g'(1),f(1),g(1)

但是可能1-vx=0

 

 

4.通分消掉分母,求导后带入1

通分,分子分母同时干掉自己的分母

A(x),C(x)都是知道的

带入1

前缀后缀积,

前缀后缀求导dp,枚举当前的(1-vx)导不导

或者发现带入1,1-x是0,可以直接对v=1特殊处理,别的含有(1-x)的连乘积都是0

 

注意:

多次进入calc

初值时,滚动数组f[0]也要先清空

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=100+5;
const int M=5e4+5;
const int NM=5e6+5;
const int mod=998244353;
int n,s[N];
int p[N];
int ad(int x,int y){
    return (x+y)>=mod?x+y-mod:x+y;
}
void inc(int &x,int y){
    x=ad(x,y);
}
int mul(int x,int y){
    return (ll)x*y%mod;
}
int qm(int x,int y=mod-2){
    int ret=1;while(y){
        if(y&1) ret=mul(ret,x);x=mul(x,x);y>>=1;
    }return ret;
}
int f[2][2*M];
struct po{
    int a,v;
}t[2*M];
int pre[2*M],bac[2*M];
int Pr[2*M],Bc[2*M];
int tot,iv,iv2;
pair<int,int>calc(int *s){
    int tmp=0;
    memset(f[tmp],0,sizeof f[tmp]);
    f[tmp][0+tot]=1;
    for(reg i=1;i<=n;++i){
        tmp^=1;
        memset(f[tmp],0,sizeof f[tmp]);
        for(reg j=-tot;j<=tot;++j){
            if(f[tmp^1][j+tot]){
                int lp=f[tmp^1][j+tot];
                inc(f[tmp][j+tot+p[i]],mul(iv2,lp));
                if(s[i]&1){
                    inc(f[tmp][j+tot-p[i]],mod-mul(iv2,lp));
                }else{
                    inc(f[tmp][j+tot-p[i]],mul(iv2,lp));
                }
            }
        }
    }
    for(reg i=-tot;i<=tot;++i){
        t[i+tot].a=f[tmp][i+tot];
        t[i+tot].v=mul(ad(mod,i),iv);

        // cout<<" i "<<i<<" a "<<t[i+tot].a<<" v "<<t[i+tot].v<<endl;

        if(i!=-tot) pre[i+tot]=mul(pre[i+tot-1],ad(1,mod-t[i+tot].v));
        else pre[i+tot]=ad(1,mod-t[i+tot].v);
        
        if(i!=-tot) Pr[i+tot]=ad(mul(Pr[i+tot-1],ad(1,mod-t[i+tot].v)),mul(pre[i+tot-1],mod-t[i+tot].v));
        else Pr[i+tot]=mod-t[i+tot].v;
    }
    for(reg i=tot;i>=-tot;--i){
        int v=t[i+tot].v;
        int now=i+tot;
        if(i!=tot) bac[now]=mul(bac[now+1],ad(1,mod-v));
        else bac[now]=ad(1,mod-v);

        if(i!=tot) Bc[now]=ad(mul(Bc[now+1],ad(1,mod-v)),mul(bac[now+1],mod-v));
        else Bc[now]=mod-v;
    }
    
    // prt(pre,0,tot+tot);
    // prt(bac,0,tot+tot);

    pii ret;ret.fi=ret.se=0;
    for(reg i=-tot;i<=tot;++i){
        int a=t[i+tot].a;
        int tmp=t[i+tot].a;
        if(i!=-tot) tmp=mul(tmp,pre[i+tot-1]);
        if(i!=tot) tmp=mul(tmp,bac[i+tot+1]);
        ret.fi=ad(ret.fi,tmp);

        tmp=0;
        int now=i+tot;
        if(i==-tot){
            tmp=mul(a,Bc[now+1]);
        }else if(i==tot){
            tmp=mul(a,Pr[now-1]);
        }else{
            tmp=ad(mul(mul(pre[now-1],a),Bc[now+1]),mul(mul(bac[now+1],a),Pr[now-1]));
        }
        ret.se=ad(ret.se,tmp);
    }
    // cout<<" ret "<<ret.fi<<" "<<ret.se<<endl;
    return ret;
}
int main(){
    rd(n);
    for(reg i=1;i<=n;++i) rd(s[i]);
    for(reg i=1;i<=n;++i) rd(p[i]),tot=ad(tot,p[i]);
    iv=qm(tot);
    iv2=qm(2); 
    
    pii A=calc(s);
    // cout<<endl<<endl;
   memset(s,0,sizeof s);
    pii C=calc(s);
    ll ans=mul(ad(mul(A.se,C.fi),mod-mul(A.fi,C.se)),qm(mul(C.fi,C.fi)));
    ot(ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

 

posted @ 2019-05-14 22:17  *Miracle*  阅读(480)  评论(0编辑  收藏  举报