• 【AGC005F】Many Easy Problems FFT 容斥原理


    题目大意

      给你一棵树,有(n)个点。还给你了一个整数(k)

      设(S)为树上某些点的集合,定义(f(S))为最小的包含(S)的联通子图的大小。

      (n)个点选(k)个点一共有(inom{n}{k})中方案,请你求出所有方案的(f(S))的和(mod 924844033)

      出题人觉得这样就太简单了,他决定让你求出所有(k=1ldots n)的答案。

      (nleq 200000)

    题解

      似乎对于每个(k)没办法快速求出答案。

      我们考虑一个点对所有答案的贡献。

      一个点(x)在这个联通子图内当且经当这(k)个点不在以(x)为根时(x)的子树内。

      那么贡献为(inom{n}{k}-sum inom{a_i}{k}),其中(a_i)为以(x)为根时各个子树的大小。可以发现,计算总的贡献时每条边两端的子树大小都会被计算一次。(inom{n}{k})会被计算(n)次。

      设

    [b_i= egin{cases} n~~~~~~~~~~(i=n)\ num_i~~~(i eq n) end{cases} ]

    其中(num_i)为大小为(i)的子树的个数

    [egin{align} ans_k&=sum_{igeq k} b_iinom{i}{k}\ &=sum_{igeq k} b_ifrac{i!}{(i-k)!k!}\ &=frac 1{k!}sum_{igeq k}b_ii! imes frac{1}{(i-k)!} end{align} ]

      这可以转化成卷积的形式

    [egin{align} c_{n-i}&=num_ii!\ d_{i}&=frac{1}{i!}\ a_i&=sum_{j+k=i}c_id_i\ ans_i&=frac{a_{n-i}}{i!} end{align} ]

      时间复杂度:(O(nlog n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<list>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const ll p=924844033;
    const ll g=5;
    ll fp(ll a,ll b)
    {
    	ll s=1;
    	while(b)
    	{
    		if(b&1)
    			s=s*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return s;
    }
    namespace ntt
    {
    	ll w1[1000010];
    	ll w2[1000010];
    	int rev[1000010];
    	int n;
    	void init()
    	{
    #ifdef DEBUG
    		n=16;
    #else
    		n=524288;
    #endif
    		int i;
    		for(i=1;i<=n;i<<=1)
    		{
    			w1[i]=fp(g,(p-1)/i);
    			w2[i]=fp(w1[i],p-2);
    		}
    		rev[0]=0;
    		for(i=1;i<n;i++)
    			rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
    	}
    	void ntt(ll *a,int t)
    	{
    		int i,j,k;
    		ll u,v,w,wn;
    		for(i=0;i<n;i++)
    			if(rev[i]<i)
    				swap(a[i],a[rev[i]]);
    		for(i=2;i<=n;i<<=1)
    		{
    			wn=(t==1?w1[i]:w2[i]);
    			for(j=0;j<n;j+=i)
    			{
    				w=1;
    				for(k=j;k<j+i/2;k++)
    				{
    					u=a[k];
    					v=a[k+i/2]*w%p;
    					a[k]=(u+v)%p;
    					a[k+i/2]=(u-v)%p;
    					w=w*wn%p;
    				}
    			}
    		}
    		if(t==-1)
    		{
    			ll inv=fp(n,p-2);
    			for(i=0;i<n;i++)
    				a[i]=a[i]*inv%p;
    		}
    	}
    };
    ll b[1000010];
    ll c[1000010];
    ll a[1000010];
    ll inv[1000010];
    ll fac[1000010];
    ll ifac[1000010];
    int s[1000010];
    int n;
    list<int> l[200010];
    ll num[1000010];
    void dfs(int x,int fa)
    {
    	s[x]=1;
    	for(auto v:l[x])
    		if(v!=fa)
    		{
    			dfs(v,x);
    			s[x]+=s[v];
    			num[s[v]]--;
    			num[n-s[v]]--;
    		}
    }
    int main()
    {
    #ifdef DEBUG
    	freopen("b.in","r",stdin);
    	freopen("b.out","w",stdout);
    #endif
    	scanf("%d",&n);
    	int i,x,y;
    	for(i=1;i<=n-1;i++)
    	{
    		scanf("%d%d",&x,&y);
    		l[x].push_back(y);
    		l[y].push_back(x);
    	}
    	inv[0]=inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
    	for(i=2;i<=n;i++)
    	{
    		inv[i]=-(p/i)*inv[p%i]%p;
    		fac[i]=fac[i-1]*i%p;
    		ifac[i]=ifac[i-1]*inv[i]%p;
    	}
    	dfs(1,0);
    	num[n]=n;
    	for(i=0;i<=n;i++)
    		b[i]=num[n-i]*fac[n-i]%p;
    	for(i=0;i<=n;i++)
    		c[i]=ifac[i];
    	ntt::init();
    	ntt::ntt(b,1);
    	ntt::ntt(c,1);
    	for(i=0;i<ntt::n;i++)
    		a[i]=b[i]*c[i]%p;
    	ntt::ntt(a,-1);
    	for(i=1;i<=n;i++)
    	{
    		ll ans=a[n-i]*ifac[i]%p;
    		ans=(ans+p)%p;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    WYT的刷子
    小烈送菜
    猴腮雷
    基于Docker的Mysql主从复制搭建
    C#集合类型大揭秘
    ASP.NET三剑客 HttpApplication HttpModule HttpHandler 解析
    使用缓存的正确姿势
    【模块化那些事】 拆散的模块化
    分享一个开源的网盘下载工具BaiduPCS-Go
    【抽象那些事】不必要的抽象
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513285.html
Copyright © 2020-2023  润新知