zoukankan      html  css  js  c++  java
  • 【CF961G】Partitions(第二类斯特林数)

    【CF961G】Partitions(第二类斯特林数)

    题面

    CodeForces
    洛谷

    题解

    考虑每个数的贡献,显然每个数前面贡献的系数都是一样的。
    枚举当前数所在的集合大小,所以前面的系数(p)就是:

    [egin{aligned} p&=sum_{i=1}^n{n-1choose i-1}iegin{Bmatrix}n-i\k-1end{Bmatrix}\ &=sum_{i=1}^n{n-1choose i-1}ifrac{1}{(k-1)!}sum_{j=0}^{k-1}(-1)^j{k-1choose j} (k-1-j)^{n-i}\ &=sum_{i=1}^n{n-1choose i-1}isum_{j=0}^{k-1}frac{(-1)^j (k-1-j)^{n-i}}{j!(k-1-j)!}\ &=sum_{j=0}^{k-1}frac{(-1)^j }{j!(k-1-j)!}sum_{i=1}^n{n-1choose i-1}i(k-1-j)^{n-i}\ end{aligned}]

    把后面一半拿出来单独算,令(t=k-1-j)

    [egin{aligned} & sum_{i=1}^n{n-1choose i-1}it^{n-i}\ &=sum_{i=1}^n frac{(n-1)!}{(i-1)!(n-i)!}it^{n-i}\ &=sum_{i=1}^n frac{(n-1)!}{(i-1)!(n-i)!}(i-1+1)t^{n-i}\ &=sum_{i=1}^n frac{(n-2)!}{(i-2)!(n-i)!}(n-1)t^{n-i}+sum_{i=1}^n frac{(n-1)!}{(i-1)!(n-i)!}t^{n-i}\ &=(n-1)sum_{i=1}^n {n-2choose i-2}t^{n-i}+sum_{i=1}^n{n-1choose i-1}t^{n-i}\ &=(n-1)sum_{i=1}^n {n-2choose n-i}t^{n-i}+sum_{i=1}^n{n-1choose n-i}t^{n-i}\ &=(n-1)(t+1)^{n-2}+(t+1)^{n-1} end{aligned}]

    所以再带回到原式中:

    [egin{aligned} p&=sum_{j=0}^{k-1}frac{(-1)^j }{j!(k-1-j)!}sum_{i=1}^n{n-1choose i-1}i(k-1-j)^{n-i}\ &=sum_{j=0}^{k-1}frac{(-1)^j }{j!(k-1-j)!}((n-1)(k-j)^{n-2}+(k-j)^{n-1})\ &=sum_{j=0}^{k-1}frac{(-1)^j }{j!(k-1-j)!}(n+k-j-1)(k-j)^{n-2} end{aligned} ]

    快速幂就完事了。


    然而我在洛谷的题解里面还看到了另外一种考虑的方法:
    考虑贡献中的(|S|sum w_i),可以认为是划分出来的集合中,每一个点都对于当前这个点贡献一次(w_i)。那么考虑当前点被其它点做的贡献次数。
    考虑一个点对((i,j)),如果(i eq j),那么方案数就是两者在同一个集合中的方案数,考虑将两个点合并在一起,那么就是(egin{Bmatrix}n-1\kend{Bmatrix}),如果(i=j),那么无论如何都有贡献,也就是(egin{Bmatrix}n\kend{Bmatrix})。所以,可以得到:

    [p=egin{Bmatrix}n\kend{Bmatrix}+(n-1)egin{Bmatrix}n\kend{Bmatrix} ]

    第二类斯特林数直接用容斥展开式计算即可,复杂度不变。

    代码是第一种方法的。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 200200
    #define MOD 1000000007
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    int fpow(int a,int b)
    {
    	int s=1;if(b<0)return 1;
    	while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
    	return s;
    }
    int n,K,ans,p;
    int jc[MAX],jv[MAX],inv[MAX];
    int main()
    {
    	scanf("%d%d",&n,&K);
    	for(int i=1,x;i<=n;++i)scanf("%d",&x),add(ans,x);
    	inv[0]=inv[1]=jc[0]=jv[0]=1;
    	for(int i=1;i<=K;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<=K;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=K;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	for(int i=0,d=1;i<K;++i,d=MOD-d)
    		add(p,1ll*d*jv[i]%MOD*jv[K-1-i]%MOD*(n+K-i-1)%MOD*fpow(K-i,n-2)%MOD);
    	ans=1ll*ans*p%MOD;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    LINUX用户管理——/etc/passwd文件详解
    接口类型的问题:信息丢失
    swift是强类型语言
    swift的多态
    面向对象的本质:基于对象+面向接口+继承
    多态的本质:同一函数接口在接受不同的类型参量时表现出不同的行为--多态是面向接口编程
    类型约束的本质是:类型构造器在约束类型的基础上构造新的函数类型
    类型与函数:函数是一种复合类型,它的构建依赖于数据类型
    类型约束的语义学研究:基于类型约束的编程
    复合类型、类型约束、添加功能、高阶函数
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10150486.html
Copyright © 2011-2022 走看看