zoukankan      html  css  js  c++  java
  • 【LuoguP4233】射命丸文的笔记-多项式求逆

    测试地址:射命丸文的笔记
    做法:本题需要用到多项式求逆。
    首先,要求存在哈密顿回路的竞赛图的哈密顿回路期望数量,就是用哈密顿回路的总数除以存在哈密顿回路的竞赛图数量。
    要考虑所有竞赛图的哈密顿回路数量之和,反过来考虑对于所有哈密顿回路,出现某回路的图的数量之和。显然对于一个回路,包含它的竞赛图数量是2n(n3)2,而一个哈密顿回路实际上就是一个1~n的圆排列,共有n!n=(n1)!种,于是我们就得到了答案:(n1)!2n(n3)2
    那么接下来就是求存在哈密顿回路的竞赛图数量了。令f(n)n个点的合法竞赛图数量,再令g(n)n个点的竞赛图数量,显然g(n)=2Cn2。我们知道,一个竞赛图存在哈密顿回路当且仅当该竞赛图强连通,因此合法竞赛图的数量就是强连通的竞赛图的数量。因此我们得到下面的式子:
    g(n)=i=1nCnif(i)g(ni)
    上面式子的含义,可以看做我们在枚举拓扑序最小的强连通分量,该强连通分量内所有的点向所有其他点连边,这样就可以不重不漏地统计竞赛图了。
    将组合数拆开,化成下面的形式:
    g(n)n!=i=1nf(i)i!g(ni)(ni)!
    F(x)f(i)i!的生成函数,G(x)g(i)i!的生成函数,则有:
    G(x)=F(x)G(x)+1
    所以:
    F(x)=G(x)1G(x)
    用多项式求逆即可在O(nlogn)的时间复杂度内解决问题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const ll G=3;
    int n,rev[400010];
    ll fac[100010],g[400010],s[400010]={0},p[400010]={0};
    
    ll power(ll a,ll b)
    {
        ll s=1,ss=a;
        b=(b%(mod-1)+(mod-1))%(mod-1);
        while(b)
        {
            if (b&1) s=s*ss%mod;
            ss=ss*ss%mod;b>>=1;
        }
        return s;
    }
    
    void NTT(ll *a,int n,ll type)
    {
        for(int i=0;i<=n;i++)
            if (i<rev[i]) swap(a[i],a[rev[i]]);
        for(int mid=1;mid<n;mid<<=1)
        {
            ll W=power(G,type*(mod-1)/(mid<<1));
            for(int l=0;l<n;l+=(mid<<1))
            {
                ll w=1;
                for(int k=0;k<mid;k++,w=w*W%mod)
                {
                    ll x=a[l+k],y=w*a[l+mid+k]%mod;
                    a[l+k]=(x+y)%mod;
                    a[l+mid+k]=(x-y+mod)%mod;
                }
            }
        }
        if (type==-1)
        {
            ll inv=power(n,mod-2);
            for(int i=0;i<n;i++)
                a[i]=a[i]*inv%mod;
        }
    }
    
    int calc_rev(int limit)
    {
        int x=1,bit=0;
        while(x<=limit) bit++,x<<=1;
        rev[0]=0;
        for(int i=1;i<x;i++)
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        return x;
    }
    
    void calc_inv(int len)
    {
        if (len==1)
        {
            s[0]=power(g[0],mod-2);
            return;
        }
        calc_inv((len+1)>>1);
    
        int x=calc_rev(len<<1);
        for(int i=0;i<len;i++)
            p[i]=g[i];
        for(int i=len;i<=x;i++)
            p[i]=0;
        NTT(p,x,1),NTT(s,x,1);
        for(int i=0;i<=x;i++)
            s[i]=((2ll*s[i]-p[i]*s[i]%mod*s[i])%mod+mod)%mod;
        NTT(s,x,-1);
        for(int i=len;i<=x;i++)
            s[i]=0;
    }
    
    int main()
    {
        scanf("%d",&n);
        fac[0]=1;
        for(ll i=1;i<=n;i++)
            fac[i]=fac[i-1]*i%mod;
    
        for(ll i=0;i<=n;i++)
            g[i]=power(2ll,i*(i-1ll)/2ll)*power(fac[i],mod-2)%mod;
        calc_inv(n+1);
    
        g[0]=0;
        int x=calc_rev(n<<1);
        NTT(g,x,1),NTT(s,x,1);
        for(int i=0;i<=x;i++)
            g[i]=g[i]*s[i]%mod;
        NTT(g,x,-1);
        for(ll i=1;i<=n;i++)
        {
            if (i<=2)
            {
                if (i==1) printf("1
    ");
                else printf("-1
    ");
            }
            else
            {
                g[i]=g[i]*fac[i]%mod;
                printf("%lld
    ",fac[i-1]*power(2ll,i*(i-3ll)/2ll)%mod*power(g[i],mod-2)%mod); 
            }
        }
    
        return 0; 
    }
  • 相关阅读:
    用纯css画个三角形
    宝塔安装
    js判断浏览器版本
    JS打开url的几种方法
    java加密算法
    Mysql数据库多对多关系未建新表
    数据库唯一性约束异常插入处理
    HTML5中localStorage的使用
    软件设计师14-UML建模
    数据库设计流程
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793291.html
Copyright © 2011-2022 走看看