zoukankan      html  css  js  c++  java
  • LuoguP4233 射命丸文的笔记

    题目描述

    求所有(n)个点带标号强连通竞赛图中哈密顿回路数量的平均值.

    题解

    因为要求平均数,所以我们可以把分母和分子单开来算。

    (n)个点的所有竞赛图的所有哈密顿回路个数是可以求出来的,就是可以枚举所有哈密顿回路,然后考虑它在多少张竞赛图中出现过,也就是:

    [ans=frac{n!}{n}2^{inom{n}{2}-n} ]

    也就是我们钦定了一条哈密顿回路之后,有(n)条边就固定不能选了,其他的边还是可以随便选的。

    由于竞赛图强连通是竞赛图具有哈密顿回路的充分必要条件。

    所以我们现在的任务就是求(n)个点的强连通竞赛图的个数。

    可以(dp)一下这个东西。

    [f[i]=2^{inom{i}{2}}-sum_{j=1}^{j<i}f[j] imes inom{i}{j} imes 2^{inom{i-j}{2}} ]

    相当于是用总数容斥掉不强连通的方案数,后面是相当于枚举当前图缩完(SCC)之后拓扑序最小的(SCC)的大小,然后其他边是可以随便连的。

    这个东西可以直接把组合数拆开(CDQ)求。

    我们可以设(g[i]=2^{inom{i}{2}})特殊的,我们令(g[0]=1,g[1]=1​)

    [f[i]=g[i]-sum_{j=1}^{j<i}frac{i!}{j!*(i-j)!}f[j] imes g[i-j] ]

    [g[i]=sum_{j=1}^{jleq i}frac{i!}{j!*(i-j)!}f[j] imes g[i-j] ]

    [frac{g[i]}{i!}=sum_{j=1}^{jleq i}frac{f[j]}{j!} imes frac{g[i-j]}{(i-j)!} ]

    这时我们可以令(G[i]=frac{g[i]}{i!},F[i]=frac{f[i]}{i!}),所以我们的形式变成了:

    [G[i]=sum_{j=1}^{j leq i}F[j]*G[j-i] ]

    然后根据分治(FFT)转多项式求逆的方法,可以表示为。

    [F*G+G_0=G ]

    [G=frac{G_0}{1-F} ]

    [F=1-frac{G_0}{G} ]

    然后就可以多项式求逆做了。

    但是我感觉这样的话常数项好像不太对,但是这道题可以把前两项判掉,所以就无关紧要了。

    代码

    #include<iostream>
    #include<cstdio>
    #define N 270009
    using namespace std;
    typedef long long ll;
    const ll G=3;
    const int Gi=332748118;
    const ll mod=998244353;
    ll g[N],b[N],c[N],jie[N],ni[N];
    int rev[N],n;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    inline void MOD(ll &x){x=x>=mod?x-mod:x;}
    inline void MOD(int &x){x=x>=mod?x-mod:x;}
    inline ll power(ll x,ll y){
    	ll ans=1;
    	while(y){if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;}
    	return ans;
    }
    inline ll gi(ll x){return power(x,mod-2);}
    inline ll C2(ll n){return n*(n-1)/2;}
    inline void NTT(ll *a,int l,int tag){
    	for(int i=1;i<l;++i)if(i>rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<l;i<<=1){
    		ll wn=power(tag==1?G:Gi,(mod-1)/(i<<1));
    		for(int j=0;j<l;j+=(i<<1)){
    			ll w=1;
    			for(int k=0;k<i;++k,w=w*wn%mod){
    				ll x=a[j+k],y=a[i+j+k]*w%mod;
    				MOD(a[j+k]=x+y);MOD(a[i+j+k]=x-y+mod);
    			}
    		}
    	}
    	if(tag<0){
    		ll ny=power(l,mod-2);
    		for(int i=0;i<l;++i)a[i]=a[i]*ny%mod;
    	}
    }
    void getinv(ll *a,int len){
    	if(len==1){b[0]=power(a[0],mod-2);return;}
    	getinv(a,(len+1)>>1);
    	int l=1,L=0;
    	while(l<=(len<<1))l<<=1,L++;
    	for(int i=1;i<l;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(L-1));
    	for(int i=0;i<len;++i)c[i]=a[i];
    	for(int i=len;i<l;++i)c[i]=0;
    	NTT(c,l,1);NTT(b,l,1);
    	for(int i=0;i<l;++i)b[i]=(2ll-c[i]*b[i]%mod+mod)*b[i]%mod;
    	NTT(b,l,-1);
    	for(int i=len;i<l;++i)b[i]=0;
    }
    int main(){
    	n=rd();
    	jie[0]=1;
    	for(int i=1;i<=n;++i)jie[i]=jie[i-1]*i%mod;ni[n]=power(jie[n],mod-2);
    	for(int i=n-1;i>=0;--i)ni[i]=ni[i+1]*(i+1)%mod;
    	g[0]=1;g[1]=1;
    	for(int i=2;i<=n;++i)g[i]=power(2,C2(i))*ni[i]%mod;
    	getinv(g,n+1);
    	for(int i=0;i<=n;++i)b[i]=(mod-b[i])*jie[i]%mod;
    	if(n>=1)puts("1");
    	if(n>=2)puts("-1");
    	for(int i=3;i<=n;++i){
    		ll num=jie[i]*gi(i)%mod*power(2,C2(i)-i)%mod;
    		printf("%lld
    ",num*gi(b[i])%mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    python实现kNN(最近邻)
    拉格朗日对偶
    拉格朗日乘子法和KKT约束
    python实现支持向量机之具体实现
    python实现支持向量机之非线性支持向量机和核函数(理论五)
    Python 装饰器实例
    Linux 系统下 matplotlib 中文乱码解决办法
    Python logging 模块学习
    Matplotlib 知识点整理
    Python Matplotlib 中文显示参数设置
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10592125.html
Copyright © 2011-2022 走看看