zoukankan      html  css  js  c++  java
  • BZOJ5093 图的价值(NTT+斯特林数)

    显然每个点会提供相同的贡献。于是现在只考虑1号点的贡献。若其度数为i,则在2~n号点选i个连上,剩下的边随便连,这样可以算出答案为

    这个式子可以O(n)计算。发现k比较小,于是考虑如何将这个式子化为与k有关的求和。

    显然前面一部分可以直接提走。考虑后面一部分的组合意义:n-1个有标号盒子里面选i个,放进去k个球的方案数

    可以对这个过程进行变换:把k个球放在n-1个有标号盒子里,有球的盒子必须选,没有的可选可不选的方案数

    枚举有球的盒子有多少个,可以发现答案变成了一个与k有关的式子:

    S(k,i)为第二类斯特林数,也即将k个小球放进i个盒子(每个盒子非空)的方案数。

    问题变为快速求斯特林数。可以用容斥原理推导出斯特林数卷积形式的通项公式:

    即给盒子标上号,枚举有几个空盒。再化一下:

    这样卷积形式就很明显了。用NTT算一下即可。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define P 998244353
    #define N 300000
    int n,k,a[N],v[N<<1],s[N<<1],inv[N],ans,ans2;
    int t,r[N<<1];
    int ksm(int a,int k)
    {
        if (k==0) return 1;
        int tmp=ksm(a,k>>1);
        if (k&1) return 1ll*tmp*tmp%P*a%P;
        else return 1ll*tmp*tmp%P;
    }
    void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
    void DFT(int n,int *a,int p)
    {
        for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
        for (int i=2;i<=n;i<<=1)
        {
            int wn=ksm(p,(P-1)/i);
            for (int j=0;j<n;j+=i)
            {
                int w=1;
                for (int k=j;k<j+(i>>1);k++,w=1ll*w*wn%P)
                {
                    int x=a[k],y=1ll*w*a[k+(i>>1)]%P;
                    a[k]=(x+y)%P;a[k+(i>>1)]=(x-y+P)%P;
                }
            }
        }
    }
    int main()
    {
        freopen("bzoj5093.in","r",stdin);
        freopen("bzoj5093.out","w",stdout);
        n=read(),k=read();
        ans=1ll*n*ksm(2,1ll*(n-1)*(n-2)/2%(P-1))%P;
        n--;
        inv[1]=1;
        for (int i=2;i<=max(3,min(n,k));i++) inv[i]=(P-1ll*(P/i)*inv[P%i]%P)%P;
        a[0]=ksm(2,n);
        for (int i=1;i<=min(n,k);i++)
        a[i]=1ll*a[i-1]*inv[2]%P*(n-i+1)%P;
        v[0]=1;
        for (int i=1;i<=min(n,k);i++)
        v[i]=(P-1ll*v[i-1]*inv[i]%P)%P;
        s[0]=0;int facinv=1;
        for (int i=1;i<=min(n,k);i++)
        {
            facinv=1ll*facinv*inv[i]%P;
            s[i]=1ll*ksm(i,k)*facinv%P; 
        }
        t=1;while (t<=(min(n,k)<<1)) t<<=1;
        for (int i=0;i<t;i++) r[i]=(r[i>>1]>>1)|(i&1)*(t>>1);
        DFT(t,s,3),DFT(t,v,3);
        for (int i=0;i<t;i++) s[i]=1ll*s[i]*v[i]%P;
        DFT(t,s,inv[3]);
        int p=ksm(t,P-2);
        for (int i=0;i<t;i++) s[i]=1ll*s[i]*p%P;
        for (int i=0;i<=min(n,k);i++)
        inc(ans2,1ll*a[i]*s[i]%P);
        ans=1ll*ans*ans2%P;
        cout<<ans;
        fclose(stdin);fclose(stdout);
        return 0;
    }
  • 相关阅读:
    点击拖动,让物体旋转
    unity中让物体不能穿到另一个物体里面去
    XML一小节
    unity中摄像机的控制---调整摄像机,不让他摔倒
    Unity 制作游侠暂停
    unity使用 NGUI制作技能冷却效果的思路
    unity中设置贴图的透明
    C#中实现打开文件夹所在的位置
    Windows下的MongoDB的安装与配置
    Scrapy运行中常见网络相关错误
  • 原文地址:https://www.cnblogs.com/Gloid/p/9390082.html
Copyright © 2011-2022 走看看