zoukankan      html  css  js  c++  java
  • 【agc005F】Many Easy Problems

    Portal --> agc005F

    Solution

    ​​  我们考虑统计每一个点的贡献,同样也是“正难则反”,(假设现在是一棵有根树,根节点是(1))发现一个点(x)对当前的选择方案没有贡献当且仅当选择的(k)个点都在(x)的某一个儿子的子树内或者都不在(x)的子树内,然后总的方案数也是很好统计的,所以我们可以考虑用减法求出一个点在选择(k)个点的情况下的贡献(val_k(x))

    ​​  

    [val_k(x)=inom n k-sumlimits_{uin son(x)}inom {size[u]} k ]

    ​​  其中(size[u])表示的是以(u)为根的子树大小

    ​​​  然后总的贡献就可以写成:

    [Ans(k)=sumlimits_{i=1}^{n}val(i)=ncdot inom n k-sumlimits_{i=1}^nsumlimits_{uin son(i)}inom {size[u]}k ]

    ​​  这个时候我们可以考虑将相同的(size[u])合并一下,记(cnt[x])表示(size=x)的节点个数:

    [Ans(k)=ncdotinom n k-sumlimits_{i=1}^{n}cnt[i]inom i k ]

    ​​​  前面的部分可以单独计算,我们将后面的sigma单独拎出来,将组合数展开:

    [egin{aligned} Ans1(k)&=sumlimits_{i=1}^n cnt[i]inom i k\ &=sumlimits_{i=1}^n cnt[i]cdot i!cdot k!cdot frac{1}{(i-k)!}\ Ans1(k)cdot k!&=sumlimits_{i=1}^n cnt[i]cdot i!cdot frac{1}{(i-k)!} end{aligned} ]

    ​​​  然后我们发现后面的那个其实是一个卷积形式,​​然后看一下这个长得很奇怪的模数:(924844033 =2^{21}*3^2*7^2+1),有个(2^{21})那所以我们可以放心NTT

    ​​​  令(A[i]=cnt[i]cdot i!),令(B[n-i]=frac{1}{(n-i)!})然后直接卷积一下即可,答案中指数为(n+k)的项的系数就是(Ans1(k))

    ​​​  然后就可以直接算了ovo

    ​ ​​  

    ​​​  代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int MOD=924844033,N=2*(1e5)+10,NT=N*4,G=5;
    struct xxx{
    	int y,nxt;
    }a[N*2];
    int h[N],fac[N],invfac[N],cnt[N],sz[N],ans[N];
    int vala[N],valb[N];
    int n,m,tot;
    int mul(int x,int y){return 1LL*x*y%MOD;}
    int add(int x,int y){return (1LL*x+y)%MOD;}
    int ksm(int x,int y){
    	int ret=1,base=x;
    	for (;y;y>>=1,base=mul(base,base))
    		if (y&1) ret=mul(ret,base);
    	return ret;
    }
    namespace NTT{/*{{{*/
    	int A[NT],B[NT],rev[NT],W[NT][2];
    	int len,invlen;
    	void init(){
    		int invg=ksm(G,MOD-2);
    		for (int i=1;i<=19;++i){
    			W[1<<i][0]=ksm(G,(MOD-1)/(1<<i));
    			W[1<<i][1]=ksm(invg,(MOD-1)/(1<<i));
    		}
    	}
    	void get_len(int n,int m){
    		for (int i=0;i<len;++i) A[i]=B[i]=0;
    		int bit=0;
    		for (len=1;len<=n+m;++bit,len<<=1);
    		rev[0]=0;
    		for (int i=1;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    		invlen=ksm(len,MOD-2);
    	}
    	void ntt(int *a,int op){
    		int w,w_n,u,v;
    		for (int i=0;i<len;++i) if (rev[i]>i) swap(a[i],a[rev[i]]);
    		for (int step=2;step<=len;step<<=1){
    			w_n=W[step][op==-1];
    			for (int st=0;st<len;st+=step){
    				w=1;
    				for (int i=0;i<(step>>1);++i){
    					v=mul(a[st+i+(step>>1)],w);
    					u=a[st+i];
    					a[st+i]=add(u,v);
    					a[st+i+(step>>1)]=add(u,MOD-v);
    					w=mul(w,w_n);
    				}
    			}
    		}
    		if (op==1) return;
    		for (int i=0;i<len;++i) a[i]=mul(a[i],invlen);
    	}
    	void Ntt(int *a,int *b,int n,int m){
    		get_len(n,m);
    		for (int i=0;i<=n;++i) A[i]=a[i];
    		for (int i=0;i<=m;++i) B[i]=b[i];
    		ntt(A,1);
    		ntt(B,1);
    		for (int i=0;i<len;++i) A[i]=mul(A[i],B[i]);
    		ntt(A,-1);
    	}
    }/*}}}*/
    void Add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
    void prework(int n){
    	NTT::init();
    	fac[0]=1;
    	for (int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
    	invfac[n]=ksm(fac[n],MOD-2);
    	for (int i=n-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1);
    }
    int C(int n,int m){return n<m?0:1LL*fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;}
    void dfs(int fa,int x){
    	int u;
    	sz[x]=1;
    	for (int i=h[x];i!=-1;i=a[i].nxt){
    		u=a[i].y;
    		if (u==fa) continue;
    		dfs(x,u);
    		sz[x]+=sz[u];
    	}
    	if (fa) ++cnt[n-sz[x]],++cnt[sz[x]];
    }
    void solve(){
    	for (int i=1;i<=n;++i) vala[i]=mul(cnt[i],fac[i]);
    	for (int i=0;i<=n;++i) valb[n-i]=invfac[i];
    	//for (int i=0;i<=n;++i) printf("%d ",vala[i]);printf("
    ");
    	//for (int i=0;i<=n;++i) printf("%d ",valb[i]);printf("
    ");
    	NTT::Ntt(vala,valb,n+1,n+1);
    	for (int i=1;i<=n;++i) ans[i]=mul(NTT::A[n+i],invfac[i]);
    	for (int i=1;i<=n;++i)
    		printf("%d
    ",add(mul(n,C(n,i)),MOD-ans[i]));
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y;
    	scanf("%d",&n);
    	memset(h,-1,sizeof(h));
    	tot=0;
    	for (int i=1;i<n;++i){
    		scanf("%d%d",&x,&y);
    		Add(x,y); Add(y,x);
    	}
    	prework(n);
    	dfs(0,1);
    	solve();
    }
    
  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9606789.html
Copyright © 2011-2022 走看看