• [ZJOI2019]开关(生成函数+背包DP)


    注:以下p[i]均表示概率

    设F(x)为按i次开关后到达终止状态方案数的EGF,显然F(x)=π(ep[i]x/p+(-1)s[i]e-p[i]x/p)/2,然而方案包含一些多次到达合法方案的状态,需将其排除。n次操作回到原状态的方案数的生成函数G(x)=π(ep[i]x/p+e-p[i]x/p)/2。实现时只需要记录F(x)=Σa[i]eix/P中a[i](-P<=i<=P)的系数即可(G(x)也一样),于是暴力复杂度O(nP)。H(x)为答案的生成函数,显然F、G、H所对应的OGF f、g、h满足f(x)=g(x)h(x)。然后就是EGF向OGF的转化:F(x)=Σa[i]eix/P→f(x)=Σa[i]/(1-ix/P),其中-P<=i<=P,于是此时要求h'(1),然后根据除法求导公式,可以计算出h'(x),但x=1时函数不收敛。然后推一下式子就发现本题其实是背包DP了(这里打数学公式太累了就省略一些内容了),复杂度O(nP)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+7,mid=1e5,mod=998244353;
    int n,sp,ans,s[N],a[N],f[N],g[N],tmp[N];
    int qpow(int a,int b)
    {
        int ret=1;
        while(b)
        {
            if(b&1)ret=1ll*ret*a%mod;
            a=1ll*a*a%mod,b>>=1;
        }
        return ret;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&s[i]);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        f[mid]=g[mid]=1;
        for(int i=1;i<=n;i++)
        {
            sp+=a[i];
            for(int j=-sp;j<=sp;j++)tmp[j+mid]=(g[j-a[i]+mid]+g[j+a[i]+mid])%mod;
            memcpy(g,tmp,sizeof g);
            for(int j=-sp;j<=sp;j++)tmp[j+mid]=(f[j-a[i]+mid]+(s[i]?mod-f[j+a[i]+mid]:f[j+a[i]+mid]))%mod;
            memcpy(f,tmp,sizeof f);
        }
        for(int i=-sp;i<sp;i++)ans=(ans+1ll*(g[i+mid]-f[i+mid]+mod)*qpow(sp-i,mod-2))%mod;
        ans=1ll*ans*sp%mod;
        printf("%d",ans);
    }
    View Code
  • 相关阅读:
    npm optionalDependencies 依赖处理
    grafana 8.0 新的报警机制
    cube.js prometheus 监控
    cube.js 新版本playground 特性
    data mesh & data lake & data fabric
    java 几个开源dataframe 的实现包
    archaius netflix 的配置管理工具框架
    dremio 文件夹数据分区
    dremio 17 发布了
    Linux系统挂载未分配硬盘空间
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10836881.html
Copyright © 2020-2023  润新知