题目:
https://csacademy.com/contest/round-32/task/sum-of-powers/
给定 N N N, M M M, K K K,考虑所有的多重子集 { a 1 , a 2 , a 3 . . . a k } \{a_1,a_2,a_3...a_k\} {a1,a2,a3...ak},满足 a 1 + a 2 + . . . + a k = N a_1+a_2+...+a_k=N a1+a2+...+ak=N,求所有的多重子集的 a 1 M + a 2 M + . . . a k M a_1^M+a_2^M+...a_k^M a1M+a2M+...akM
思路:
首先因为是多重子集,所以等价于特殊背包,但如果是在
d
p
dp
dp的过程中维护要求的值,那么转移的时候很麻烦。所以还是维护方案数。令
f
(
i
,
j
)
f(i,j)
f(i,j)表示当前有
i
i
i个数字,和为
j
j
j且是非递增序列的方案数。然后考虑每个数字
x
x
x的贡献。
x
的
总
次
数
=
(
x
刚
好
出
现
1
次
的
方
案
数
)
+
(
x
刚
好
出
现
2
次
的
方
案
数
)
∗
2...
=
(
x
至
少
出
现
1
次
的
方
案
数
)
+
(
x
刚
好
出
现
2
次
的
方
案
数
)
+
.
.
.
=
f
(
i
−
1
,
j
−
x
)
+
f
(
i
−
2
,
j
−
2
x
)
+
.
.
.
\begin{aligned} x的总次数&=(x刚好出现1次的方案数)+(x刚好出现2次的方案数)*2...\\ &=(x至少出现1次的方案数)+(x刚好出现2次的方案数)+...\\ &=f(i-1,j-x)+f(i-2,j-2x)+... \end{aligned}
x的总次数=(x刚好出现1次的方案数)+(x刚好出现2次的方案数)∗2...=(x至少出现1次的方案数)+(x刚好出现2次的方案数)+...=f(i−1,j−x)+f(i−2,j−2x)+...
#include <bits/stdc++.h>
using namespace std;
const int N=5e3+50, mod=1e9+7;
inline int add(int x, int y) {
return (x+y>=mod) ? (x+y-mod) : (x+y);
}
inline int dec(int x, int y) {
return (x-y<0) ? (x-y+mod) : (x-y);
}
inline int mul(int x, int y) {
return ((unsigned long long)x*y%mod);
}
inline int power(int a,int b,int rs=1) {
for(; b; b>>=1,a=mul(a,a))
if(b&1)
rs=mul(rs,a);
return rs;
}
int n,m,k,ans,f[N][N];
int main() {
cin>>n>>k>>m;
f[0][0]=1;
for(int i=1; i<=n; i++)
for(int j=1; j<=i && j<=k; j++)
f[i][j]=add(f[i-j][j],f[i-1][j-1]);
for(int i=1,pw=1; i<=n; i++,pw=power(i,m))
for(int j=1; j*i<=n && j<=k; ++j)
ans=add(ans,mul(f[n-i*j][k-j],pw));
cout<<ans<<endl;
}