zoukankan      html  css  js  c++  java
  • 有标号DAG计数

    有标号DAG计数

    题目大意:求(n)个点有标号弱连通( ext{DAG})数量

    如果你做过类似 「CEOI2019」游乐园 这样常见的( ext{DAG})计数问题

    就会对于统计( ext{DAG})数量的这个容斥方法十分熟悉

    枚举图分层,设当前已经确定的层中点集为(S),下一层点集为(T)

    (dp_{S+T}leftarrow dp_{S} imes 2^{|S|cdot |T|}(-1)^{|T|+1})

    其中(|S|cdot |T|)为层间随意连的边数量,((-1)^{|T|+1})是针对分层不唯一的容斥

    当然这样统计出的( ext{DAG})是不连通的

    那么我们先考虑用卷积来维护这样的一个图

    设分层大小为(a_i,iin[1,m],n=sum a_i),则上式的变化形式就是

    (displaystyle frac{displaystyle n!2^{inom{n}{2}}}{displaystyle prod a_i!(-1)^{a_i+1}2^{inom{a_i}{2}}})

    其中(displaystyle inom{n}{2}-sum inom{a_i}{2})就能得出层间边的数量

    那么令(displaystyle F(x)=sum_{nge 1}frac{(-1)^{n+1}}{n!2^{inom{n}{2}}}) ,由于层间有序,答案是

    (displaystyle G(x)=sum F^i(x)=frac{1}{1-F(x)})

    求逆一次即可得到(G(x)),然后补上式子中的系数(displaystyle 2^{inom{n}{2}})

    显然不连通的( ext{DAG})转为连通( ext{DAG})只需要再求一次$ln $即可

    注意计算的时候是以( ext{EGF})的形式,最后要补回阶乘

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef pair <int,int> Pii;
    typedef vector <int> V;
    #define reg register
    #define mp make_pair
    #define pb push_back
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    
    #ifndef ONLINE_JUDGE
    #define LOG(...) fprintf(stderr,__VA_ARGS__)
    #else
    #define LOG(...) 
    #endif
    
    char IO;
    template <class T=int> T rd(){
    	T s=0; int f=0;
    	while(!isdigit(IO=getchar())) f|=IO=='-';
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int L=18,N=1<<L|10,P=998244353;
    
    ll qpow(ll x,ll k=P-2) {
    	ll res=1;
    	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
    	return res;
    }
    
    int I[N],J[N];
    int rev[N],w[N];
    void Init(){
    	w[1<<(L-1)]=1;
    	int t=qpow(3,(P-1)>>L);
    	rep(i,(1<<(L-1))+1,1<<L) w[i]=1ll*w[i-1]*t%P;
    	drep(i,(1<<(L-1))-1,1) w[i]=w[i<<1];
    	rep(i,J[0]=1,N-1) J[i]=1ll*J[i-1]*i%P;
    	I[N-1]=qpow(J[N-1]);
    	drep(i,N-1,1) I[i-1]=1ll*I[i]*i%P;
    }
    int Init(int n){
    	int R=1,c=-1;
    	while(R<=n) R<<=1,c++;
    	rep(i,0,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<c);
    	return R;
    }
    void NTT(int n,V &A,int f) {
    	static ull a[N];
    	if((int)A.size()<n) A.resize(n);
    	rep(i,0,n-1) a[rev[i]]=A[i];
    	for(int i=1;i<n;i<<=1) {
    		int *e=w+i;
    		for(int l=0;l<n;l+=i*2) {
    			for(int j=l;j<l+i;++j) {
    				int t=a[j+i]*e[j-l]%P;
    				a[j+i]=a[j]+P-t;
    				a[j]+=t;
    			}
    		}
    	}
    	rep(i,0,n-1) A[i]=a[i]%P,Mod2(A[i]);
    	if(f==-1) {
    		reverse(A.begin()+1,A.end());
    		ll base=1ll*I[n]*J[n-1]%P;
    		rep(i,0,n-1) A[i]=A[i]*base%P;
    	}
    }
    
    V operator + (V a,const V &b) {
    	if(a.size()<b.size()) a.resize(b.size());
    	rep(i,0,b.size()-1) a[i]+=b[i],Mod1(a[i]);
    	return a;
    }
    V operator - (V a,const V &b) {
    	if(a.size()<b.size()) a.resize(b.size());
    	rep(i,0,b.size()-1) a[i]-=b[i],Mod2(a[i]);
    	return a;
    }
    V operator * (V a,V b) {
    	int n=a.size()-1,m=b.size()-1;
    	int R=Init(n+m);
    	NTT(R,a,1),NTT(R,b,1);
    	rep(i,0,R-1) a[i]=1ll*a[i]*b[i]%P;
    	NTT(R,a,-1),a.resize(n+m+1);
    	return a;
    }
    void println(const V &a){
    	for(int i:a) printf("%d ",i);
    	puts("");
    }
    V read(int n){
    	V A(n);
    	rep(i,0,n-1) A[i]=rd();
    	return A;
    }
    V operator ~ (V a) {
    	int n=a.size(),m=(n+1)>>1;
    	if(n==1) return {(int)qpow(a[0])};
    	V b=a; b.resize(m),b=~b;
    	int R=Init(n*2);
    	NTT(R,a,1),NTT(R,b,1);
    	rep(i,0,R-1) a[i]=(P+2-1ll*a[i]*b[i]%P)*b[i]%P;
    	NTT(R,a,-1),a.resize(n);
    	return a;
    }
    V Deriv(V a) {
    	rep(i,0,a.size()-2) a[i]=1ll*(i+1)*a[i+1]%P;
    	a.pop_back();
    	return a;
    }
    V Integ(V a){
    	a.pb(0);
    	drep(i,a.size()-1,1) a[i]=1ll*a[i-1]*J[i-1]%P*I[i]%P;
    	a[0]=0;
    	return a;
    }
    V Ln(V a){
    	int n=a.size();
    	a=Deriv(a)*~a;
    	return a.resize(n-1),Integ(a);
    }
    int Div2(int x){ return (x&1?x+P:x)/2; }
    int Pow[N],IPow[N];
    
    int main(){
    	int n=rd();
    	Init();
    	Pow[0]=Pow[1]=IPow[0]=IPow[1]=1;
    	for(int i=2,x=2,y=(P+1)/2;i<N;i++,x*=2,Mod1(x),y=Div2(y)) {
    		Pow[i]=1ll*Pow[i-1]*x%P;
    		IPow[i]=1ll*IPow[i-1]*y%P;
    	}
    	V F(n+1);
    	rep(i,1,n) {
    		F[i]=1ll*I[i]*IPow[i]%P;
    		if(~i&1) F[i]=-F[i],Mod2(F[i]); // 这个是容斥系数 
    		F[i]=P-F[i];// 这个是1-F
    	}
        // 这个是1-F
    	F[0]=1;
    	F=~F;
    	rep(i,0,n) F[i]=1ll*F[i]*Pow[i]%P;
        // 补回系数,然后做一次ln
    	F=Ln(F);
    	rep(i,0,n) F[i]=1ll*F[i]*J[i]%P;
    	rep(i,1,n) printf("%d
    ",F[i]);
    }
    
  • 相关阅读:
    js浏览器对象
    js对象
    js基础
    css的常见操作
    css 盒子模型
    css定位与浮动
    汇编三(习题)
    pyEcharts安装及使用指南(最新)
    pyEcharts安装及使用指南
    Anaconda安装第三方库与pip和conda 添加国内源
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14567079.html
Copyright © 2011-2022 走看看