• 7.11 NOI模拟赛 graph 生成函数 dp 多项式


    LINK:graph

    HDU题库里的原题 没做过自闭。

    考虑dp 设(f_{i,j})表示前i个点构成j个联通块是树的方案数。

    对于一次询问答案即为(sum_{j}f_{n,j}j^k)

    考虑如何dp出来 显然每次枚举1号所在的连通块的大小 考虑这个连通块是否构成树 即可。

    具体转移不再赘述 需要预处理一下i个点的树的个数 i个点的连通块个数 i个点不是树是连通块的个数。

    复杂度(n^3) 利用分治NTT来优化可以到 (n^2log^2)比较繁杂且不是正解。

    正解当然是考虑生成函数。

    (T(x))表示i个点的生成树个数的EGF G(x)为i个点连通块个数的EGF F_{w}(x)表示k值为w时的答案的EGF E(x)为i个点联通但不是树的生成树个数.

    那么显然有(E(x)=e^{G(x)-T(x)},F_{w}(x)=sum_{i}frac{i^wcdot T^i(x)}{i!}E(x))

    显然当w==1时可以化简 这启示我们利用自然幂转斯特林数(x^k=sum_{i}x^underline{i}cdot s(k,i))

    然后可以化简得到 (f_{k}(x)=sum_x^k s(k,x)cdot e^{T(y)}E(y)T^x(y))

    设H(x)表示i个点的图的个数。

    那么有(H(x)=E(x)cdot e^{T(x)})

    可得 (f_{k}(x)=sum_{x=0}^k s(k,x)cdot H(y)T^x(y))

    预处理(knlogn) 查询 (Tk)

    值得一提的是 T(x)的第0项是0 因为如果为1答案是错误的 而H(x)第0项是1 因为可以上面的定义式计算出来为1.

    code bf
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 2000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-8
    #define sq sqrt
    #define S second
    #define F first
    #define mod 998244353
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=1010;
    int n=100,k,T;
    int f1[MAXN],f2[MAXN],f3[MAXN],sum[21][MAXN];
    int f[MAXN][MAXN],g[MAXN],inv[MAXN],fac[MAXN];
    //f1[i]表示i个点形成的树的个数.f2[i]表示i个点形成连通块但不是树的方案数.f3[i]表示i个点形成的连通块的方案数.
    //f[i][j]表示i个点形成j棵树的方案数.
    inline int ksm(int b,int p)
    {
    	int cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=(ll)cnt*b%mod;
    		b=(ll)b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline int mul(int a,int b){return (ll)a*b%mod;}
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline int mus(int a,int b){return a-b<0?a-b+mod:a-b;}
    inline int C(int a,int b){return a<b?0:(ll)fac[a]*inv[b]%mod*inv[a-b]%mod;}
    int main()
    {
    	freopen("xuanyiming.in","r",stdin);
        freopen("xuanyiming.out","w",stdout);
    	f3[1]=f1[1]=fac[0]=fac[1]=1;
    	rep(2,n,i)f1[i]=ksm(i,i-2),fac[i]=mul(fac[i-1],i);
    	inv[n]=ksm(fac[n],mod-2);
    	fep(n-1,0,i)inv[i]=mul(inv[i+1],i+1);
    	rep(2,n,i)
    	{
    		f3[i]=ksm(2,i*(i-1)/2);
    		rep(1,i-1,j)
    		{
    			f3[i]=mus(f3[i],mul(mul(C(i-1,j-1),f3[j]),ksm(2,(i-j)*(i-j-1)/2)));
    		}
    		f2[i]=mus(f3[i],f1[i]);
    	}
    	f[0][0]=1;f[1][1]=1;
    	rep(2,n,i)
    	{
    		rep(0,i,j)
    		{
    			rep(1,i,k)
    			{
    				//不做贡献.
    				f[i][j]=add(f[i][j],mul(mul(C(i-1,k-1),f2[k]),f[i-k][j]));
    				//做贡献
    				if(j>=1)f[i][j]=add(f[i][j],mul(mul(C(i-1,k-1),f1[k]),f[i-k][j-1]));
    			}
    		}
    	}
    	rep(1,n,j)
    	{
    		int ww=j;
    		rep(1,20,c)
    		{
    			rep(j,n,i)sum[c][i]=add(sum[c][i],mul(ww,f[i][j]));
    			ww=mul(ww,j);
    		}
    	}
    	get(T);
    	while(T--)
    	{
    		get(n);get(k);
    		put(sum[k][n]);
    	}
    	return 0;
    }
    
    code sol
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 10000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define S second
    #define F first
    #define mod 998244353
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=200010,maxn=21,G=3;
    int A[MAXN],fac[MAXN],inv[MAXN],rev[MAXN],B[MAXN],C[MAXN],D[MAXN],O[MAXN];
    int n,T,k,lim;
    int s[maxn][maxn];
    int F[maxn][MAXN];
    inline int ksm(int b,int p)
    {
    	p%=mod-1;
    	int cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=(ll)cnt*b%mod;
    		b=(ll)b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline void NTT(int *a,int op)
    {
    	vep(0,lim,i)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int len=2;len<=lim;len=len<<1)
    	{
    		int mid=len>>1;
    		int wn=ksm(G,op==1?(mod-1)/len:mod-1-(mod-1)/len);
    		vep(1,mid,i)O[i]=(ll)O[i-1]*wn%mod;
    		for(int j=0;j<lim;j+=len)
    		{
    			vep(0,mid,i)
    			{
    				int x=a[i+j],y=(ll)a[i+j+mid]*O[i]%mod;
    				a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
    			}
    		}
    	}
    	if(op==-1)
    	{
    		int INV=ksm(lim,mod-2);
    		vep(0,lim,i)a[i]=(ll)a[i]*INV%mod;
    	}
    }
    int main()
    {
    	freopen("xuanyiming.in","r",stdin);
        freopen("xuanyiming.out","w",stdout);
    	s[1][1]=1;k=20;n=50000;fac[0]=O[0]=1;
    	rep(1,n,i)fac[i]=(ll)fac[i-1]*i%mod;
    	inv[n]=ksm(fac[n],mod-2);
    	fep(n-1,0,i)inv[i]=(ll)inv[i+1]*(i+1)%mod;
    	rep(2,k,i)rep(1,i,j)s[i][j]=(s[i-1][j-1]+(ll)j*s[i-1][j])%mod;
    	B[0]=B[1]=A[1]=1;rep(2,n,i)A[i]=(ll)ksm(i,i-2)*inv[i]%mod,B[i]=(ll)ksm(2,(ll)(i-1)*i/2)*inv[i]%mod;
    	lim=1;while(lim<=n+n)lim=lim<<1;
    	vep(1,lim,i)rev[i]=rev[i>>1]>>1|((i&1)?lim>>1:0);
    	NTT(A,1);NTT(B,1);
    	vep(0,lim,i)C[i]=(ll)A[i]*B[i]%mod;
    	NTT(C,-1);vep(n+1,lim,i)C[i]=0;
    	rep(1,k,j)
    	{
    		rep(0,n,i)F[j][i]=(ll)C[i]*fac[i]%mod;
    		NTT(C,1);
    		vep(0,lim,i)C[i]=(ll)C[i]*A[i]%mod;
    		NTT(C,-1);vep(n+1,lim,i)C[i]=0;
    	}
    	get(T);
    	while(T--)
    	{
    		get(n);get(k);
    		int ans=0;rep(1,k,i)ans=(ans+(ll)s[k][i]*F[i][n])%mod;
    		put(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Cocos Creator代码编辑环境配置
    CocosCreator编辑器界面
    Colored Sticks (并查集+Trie + 欧拉路)
    子序列 NYOJ (尺取法+队列+hash) (尺取法+离散化)
    相同的雪花 Hash
    F
    逆序数
    士兵杀敌5 前缀数组
    Color the ball 线段树 区间更新但点查询
    士兵杀敌(二) 线段树
  • 原文地址:https://www.cnblogs.com/chdy/p/13289405.html
Copyright © 2020-2023  润新知