zoukankan      html  css  js  c++  java
  • [CF932E]Team Work & [BZOJ5093]图的价值

    CF题面
    题意:求(sum_{i=0}^{n}inom{n}{i}i^k)
    (nle10^9,kle5000)
    (10^9+7)
    BZOJ题面
    题意:求(n*2^{frac{n(n-1))}{2}-(n-1)}*sum_{i=0}^{n-1}inom{n-1}{i}i^k)
    (nle10^9,kle2*10^5)
    (998244353)

    第二类斯特林数

    赶紧去学第二类斯特林数啊
    第二类斯特林数:(S(n,m)),表示把(n)个不同的的球放到(m)个相同的盒子且不允许空盒的方案数。
    首先有一个(O(n^2))的递推。考虑第(n)个球的放置,如果单独放置方案数就等于(S(n-1,m-1)),否则就是(m*S(n-1,m)),表示枚举放在那个盒子里。写出来就是

    [S(n,m)=S(n-1,m-1)+m*S(n-1,m) ]

    边界条件:(S(0,0)=1,S(i,0)=0(i>0))
    然后还有各种考虑组和意义得出来的柿子
    第二类斯特林数存在通项公式。因为(m^n)表示把(n)个不同的球放到(m)个不同的盒子里且允许空盒的方案数,我们想办法用这个东西构造出第二类斯特林数的组和意义。
    首先盒子是否相同很好办,直接乘/除以(m!)即可。关键问题在于空盒的处理。
    考虑容斥,计算“至少有(k)个空盒然后剩下的随便是不是空盒的方案数”,乘上一个容斥系数

    [S(n,m)=frac{1}{m!}sum_{k=0}^{m}(-1)^kinom{m}{k}(m-k)^n ]

    还有一个,反过来用第二类斯特林数来表示(m^n)
    其实就是一个反演,但如果也同样考虑组和意义的话岂不妙哉。
    枚举有几个盒子不是空的,可以直接得到如下柿子:

    [m^n=sum_{i=0}^{m}S(n,i)*inom{m}{i}*i! ]

    sol

    所以说这道题怎么做呢?
    开始推柿子辣~

    [sum_{i=0}^{n}inom{n}{i}i^k=sum_{i=0}^{n}inom{n}{i}sum_{j=0}^{i}S(k,j)*inom{i}{j}*j!\=sum_{j=0}^{n}S(k,j)*j!sum_{i=j}^{n}inom{n}{i}inom{i}{j}\=sum_{j=0}^{n}S (k,j)*j!*inom{n}{j}*2^{n-j}\=sum_{j=0}^{k}S (k,j)*j!*inom{n}{j}*2^{n-j}]

    注意(sum_{i=j}^{n}inom{n}{i}inom{i}{j})的组合意义:从(n)个里面选出任意多个(大于等于(j))再从中选出(j)个,相当于从(n)个中选(j)个然后剩下的(n-j)个随便选。
    柿子里面的阶乘(j!)、组合数(inom{n}{j})、2的次幂(2^{n-j})都可以(O(k))处理出来。复杂度瓶颈在于第二类斯特林数的处理。
    (kle5000)可以直接用递推式(O(k^2))处理出来,而观察其通项式会发现其实就是一个卷积形式:

    [S(n,m)=frac{1}{m!}sum_{k=0}^{m}(-1)^kinom{m}{k}(m-k)^n\=sum_{k=0}^{m}frac{(-1)^k}{k!}*frac{(m-k)^n}{(m-k)!} ]

    所以直接上(NTT),复杂度(O(klog{k}))
    但是(CF)上的那道题不能用(NTT)诶,毕竟(10^9+7)怎么(NTT)(我没说不可以啊,只是我还不会呀。。。)

    update 3.28 放心(MTT)这个坑已经填了。

    code

    [CF932E]Team Work
    这里我强行用通项公式然后写了个(O(k^2))的多项式乘法

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int mod = 1e9+7;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    int fastpow(int a,int b)
    {
    	int res=1;
    	while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    	return res;
    }
    const int N = 5005;
    int jc[N],C[N],two[N],inv,a[N],b[N],s[N],ans;
    int main()
    {
    	int n=gi(),k=gi();
    	jc[0]=1;
    	for (int i=1;i<=k;++i) jc[i]=1ll*jc[i-1]*i%mod;
    	C[0]=1;
    	for (int i=1;i<=k;++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*fastpow(i,mod-2)%mod;
    	two[0]=fastpow(2,n);inv=fastpow(2,mod-2);
    	for (int i=1;i<=k;++i) two[i]=1ll*two[i-1]*inv%mod;
    	for (int i=0;i<=k;++i) a[i]=i&1?mod-fastpow(jc[i],mod-2):fastpow(jc[i],mod-2);
    	for (int i=0;i<=k;++i) b[i]=1ll*fastpow(i,k)*fastpow(jc[i],mod-2)%mod;
    	for (int i=0;i<=k;++i)
    		for (int j=0;j<=i;++j)
    			(s[i]+=1ll*a[j]*b[i-j]%mod)%=mod;
    	for (int i=1;i<=k;++i) (ans+=1ll*s[i]*jc[i]%mod*C[i]%mod*two[i]%mod)%=mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    

    [BZOJ5093]图的价值

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int _ = 800005;
    const int mod = 998244353;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    int fastpow(int a,int b)
    {
    	int res=1;
    	while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    	return res;
    }
    int n,N,k,l;
    int jc[_],C[_],two[_],inv,a[_],b[_],rev[_],ans;
    void NTT(int *P,int opt)
    {
    	for (int i=0;i<N;++i) if (i>rev[i]) swap(P[i],P[rev[i]]);
    	for (int i=1;i<N;i<<=1)
    	{
    		int W=fastpow(3,(mod-1)/(i<<1));
    		if (opt==-1) W=fastpow(W,mod-2);
    		for (int j=0,p=i<<1;j<N;j+=p)
    		{
    			int w=1;
    			for (int k=0;k<i;++k,w=1ll*w*W%mod)
    			{
    				int x=P[j+k],y=1ll*P[j+k+i]*w%mod;
    				P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod;
    			}
    		}
    	}
    	if (opt==-1)
    	{
    		int Inv=fastpow(N,mod-2);
    		for (int i=0;i<N;++i) P[i]=1ll*P[i]*Inv%mod;
    	}
    }
    int main()
    {
    	n=gi()-1;k=gi();
    	jc[0]=1;
    	for (int i=1;i<=k;++i) jc[i]=1ll*jc[i-1]*i%mod;
    	C[0]=1;
    	for (int i=1;i<=k;++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*fastpow(i,mod-2)%mod;
    	two[0]=fastpow(2,n);inv=fastpow(2,mod-2);
    	for (int i=1;i<=k;++i) two[i]=1ll*two[i-1]*inv%mod;
    	for (int i=0;i<=k;++i) a[i]=i&1?mod-fastpow(jc[i],mod-2):fastpow(jc[i],mod-2);
    	for (int i=0;i<=k;++i) b[i]=1ll*fastpow(i,k)*fastpow(jc[i],mod-2)%mod;
    	for (N=1;N<=k*2;N<<=1) ++l;--l;
    	for (int i=0;i<N;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
    	NTT(a,1);NTT(b,1);
    	for (int i=0;i<N;++i) a[i]=1ll*a[i]*b[i]%mod;
    	NTT(a,-1);
    	for (int i=0;i<=k;++i) (ans+=1ll*a[i]*jc[i]%mod*C[i]%mod*two[i]%mod)%=mod;
    	int Pow=(1ll*n*(n+1)/2-n)%(mod-1);
    	printf("%d
    ",1ll*ans*fastpow(2,Pow)%mod*(n+1)%mod);
    	return 0;
    }
    
  • 相关阅读:
    汤姆猫解决打印日志乱码问题
    oracel如何将timestamp转化为date类型
    oracle排序分页
    批量删除某一后缀的临时表
    oracle分组排序后获取每组行号
    cxf中隐藏服务列表
    怎么从一张表中查询数据插入到另一张表中
    weblogic创建域
    java多线程
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8450141.html
Copyright © 2011-2022 走看看