【CF961G】Partitions(第二類斯特林數)
題面
CodeForces
洛谷
題解
考慮每個數的貢獻,顯然每個數前面貢獻的系數都是一樣的。
枚舉當前數所在的集合大小,所以前面的系數\(p\)就是:
\[\begin{aligned} p&=\sum_{i=1}^n{n-1\choose i-1}i\begin{Bmatrix}n-i\\k-1\end{Bmatrix}\\ &=\sum_{i=1}^n{n-1\choose i-1}i\frac{1}{(k-1)!}\sum_{j=0}^{k-1}(-1)^j{k-1\choose j} (k-1-j)^{n-i}\\ &=\sum_{i=1}^n{n-1\choose i-1}i\sum_{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-1\choose i-1}i(k-1-j)^{n-i}\\ \end{aligned}\]
把后面一半拿出來單獨算,令\(t=k-1-j\)
\[\begin{aligned} &\ \ \ \sum_{i=1}^n{n-1\choose 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-2\choose i-2}t^{n-i}+\sum_{i=1}^n{n-1\choose i-1}t^{n-i}\\ &=(n-1)\sum_{i=1}^n {n-2\choose n-i}t^{n-i}+\sum_{i=1}^n{n-1\choose n-i}t^{n-i}\\ &=(n-1)(t+1)^{n-2}+(t+1)^{n-1} \end{aligned}\]
所以再帶回到原式中:
\[ \begin{aligned} p&=\sum_{j=0}^{k-1}\frac{(-1)^j }{j!(k-1-j)!}\sum_{i=1}^n{n-1\choose 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\neq j\),那么方案數就是兩者在同一個集合中的方案數,考慮將兩個點合并在一起,那么就是\(\begin{Bmatrix}n-1\\k\end{Bmatrix}\),如果\(i=j\),那么無論如何都有貢獻,也就是\(\begin{Bmatrix}n\\k\end{Bmatrix}\)。所以,可以得到:
\[p=\begin{Bmatrix}n\\k\end{Bmatrix}+(n-1)\begin{Bmatrix}n\\k\end{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\n",ans);return 0;
}