zoukankan      html  css  js  c++  java
  • 有标号的DAG图计数1~4

    前言

    我什么都不会,菜的被关了起来。

    有标号的DAG图I

    Solution

    考虑递推,设(f_i)表示i个点的答案,显然这个东西是可以组合数+容斥递推?

    (f_i)表示i个点的答案,我们考虑假设现在有j个点入度为1,那么可以选出的点就是一个组合数(C_i^j),边的可能性有两种,对应的就是(2^{j*(i-j)}),然后接着搞,肯定这样子算会有重复的,所以容斥一下然后和以前的答案乘起来就好了。

    (f_i=sum_{j=1}^{i}f_{i-j}*-1^{j-1}*C_i^j*2^{j*(i-j)})

    然后就可以递推了。

    上面虽然不是瞎扯,但是完全过不了本题 90分了解一下

    所以需要运用的是什么?

    当然是预处理啊(辣鸡出题人卡常数)

    代码实现

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int Mod=1e4+7;
    int c[5010][5010],f[5010],two[25000010];
    int main(){
    	re int n=gi();two[0]=1;
    	for(int i=1;i<=n*n/4;i++){
    		two[i]=two[i-1]<<1;
    		if(two[i]>=Mod)two[i]-=Mod;
    	}
    	c[0][0]=1;
    	for(re int i=1;i<=n;i++){
    		c[i][0]=1;
    		for(re int j=1;j<=n;j++){
    			c[i][j]=(c[i-1][j]+c[i-1][j-1]);
    			if(c[i][j]>=Mod)c[i][j]-=Mod;
    		}
    	}
    	f[0]=f[1]=1;
    	for(re int i=2;i<=n;i++)
    		for(re int j=1,d=1;j<=i;j++,d=-d){
    			f[i]+=(ll)(c[i][j]*f[i-j]%Mod*two[j*(i-j)]%Mod*d)%Mod;
    			while(f[i]<0)f[i]+=Mod;
    			while(f[i]>=Mod)f[i]-=Mod;
    		}
    	printf("%d
    ",f[n]);
    	return 0;
    }
    

    有标号的DAG图计数II

    Solution

    考虑上面的式子怎么搞?

    发现如果想要卷积优化肯定只能够把2的次方拆开啊。

    [j*(i-j)=i*j-j^2 \ =frac{i^2}{2}-frac{j^2}{2}-frac{(i-j)^2}{2} ]

    化成这个形式直接二次剩余随便搞就好了。

    P.S:如果不会多项式求逆就看这个

    代码实现

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    const int N=300010,Mod=998244353,REM=882049182;
    int r[N],c[N],F[N],G[N],inv[N],jc[N],jcn[N];
    int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=(ll)ret*a%Mod;a=(ll)a*a%Mod;b>>=1;};return ret;}
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    void NTT(int *P,int opt,int limit){
    	for(int i=0;i<limit;i++)if(i<r[i])swap(P[i],P[r[i]]);
    	for(int i=1;i<limit;i<<=1){
    		int w=qpow(3,(Mod-1)/(i<<1));
    		for(int p=i<<1,j=0;j<limit;j+=p){
    			int W=1;
    			for(int k=0;k<i;k++,W=(1ll*W*w)%Mod){
    				int X=P[j+k],Y=(ll)P[i+j+k]*W%Mod;
    				P[j+k]=(X+Y)%Mod;P[i+j+k]=(X-Y+Mod)%Mod;
    			}	
    		}
    	}
    	if(opt==-1){
    		reverse(P+1,P+limit);
    		for(int i=0,inv=qpow(limit,Mod-2);i<limit;i++)P[i]=1ll*P[i]*inv%Mod;
    	}
    }
    void Inv(int *a,int *b,int len){
    	if(len==1){b[0]=qpow(a[0],Mod-2);return;}
    	Inv(a,b,(len+1)>>1);
    	int l=0,limit=1;
    	while(limit<(len<<1))limit<<=1,l++;
    	for(int i=0;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=0;i<limit;i++)c[i]=a[i];
    	for(int i=len;i<limit;i++)c[i]=0;
    	NTT(c,1,limit);NTT(b,1,limit);
    	for(int i=0;i<limit;i++)b[i]=1ll*(2-1ll*c[i]*b[i]%Mod+Mod)%Mod*b[i]%Mod;
    	NTT(b,-1,limit);
    	for(int i=len;i<limit;i++)b[i]=0;
    }
    int main(){
    	int n=gi();
    	jc[0]=jcn[0]=inv[1]=1;
    	for(int i=1;i<=n;i++)jc[i]=(ll)jc[i-1]*i%Mod;
    	for(int i=2;i<=n;i++)inv[i]=(ll)(Mod-Mod/i)*inv[Mod%i]%Mod;
    	for(int i=1;i<=n;i++)jcn[i]=(ll)jcn[i-1]*inv[i]%Mod;
    	G[0]=1;
    	int Limit=1;while(Limit<=n)Limit<<=1;int t=qpow(REM,Mod-2);
    	for(int i=1;i<Limit;i++)G[i]=1ll*jcn[i]*qpow(t,1ll*i*i%(Mod-1))%Mod;
    	for(int i=1;i<Limit;i++)if(i&1)G[i]=Mod-G[i];
    	Inv(G,F,Limit);
    	printf("%lld
    ",1ll*F[n]*jc[n]%Mod*qpow(REM,1ll*n*n%(Mod-1))%Mod);
    	return 0;
    }
    
  • 相关阅读:
    蜂窝网格的坐标以及寻路
    unity3d 第三人称视角的人物移动以及相机控制
    基本HTML结构
    平衡二叉树
    STL基础复习
    递归
    unity 傅老师学习
    blender基础操作
    最小生成树
    最短路径
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10284682.html
Copyright © 2011-2022 走看看