【AtCoder Regular Contest 059 E】Children and Candies
DP。
题目大意:
给定 $n$ 个人和 $a$ 个糖。
一个人喜悦值为 $x_i$,分到 $c$ 颗糖,则他的贡献为 $x_i^c$。一种分糖方案的总贡献为每个人的贡献的乘积。
定义 $f(x_1,x_2,x_3,\ldots,x_n)$ 表示每个人的喜悦值分别为 $x_1,x_2,x_3,\ldots,x_n$ 时,分完所有糖的所有不同方案的贡献之和。
求:
题解:
当确定一组 $x$ 的时候,我们可以直接做一个背包问题。时间复杂度 $O(n^3)$。
我们要求的是乘积的和,不难发现一个 $x$ 的所有取值是可以在一起计算的。
所以我们将所有取值一起算就好了。需要预处理 $k$ 次方前缀和。
时间复杂度 $O(n^3)$。
Code:
#include<cstdio>
typedef long long LL;
const int N=405,md=1e9+7;
int n,c,A[N],B[N],dp[N];
int pre[N][N],pw[N];
inline void upd(int&a){a+=a>>31&md;}
int main(){
scanf("%d%d",&n,&c);
for(int i=1;i<=n;++i)scanf("%d",A+i);
for(int i=1;i<=n;++i)scanf("%d",B+i);
dp[0]=1;
for(int i=1;i<=400;++i)pw[i]=1;
for(int i=0;i<=c;++i){
int*P=pre[i];
for(int j=1;j<=400;++j)upd(P[j]=P[j-1]+pw[j]-md),pw[j]=(LL)pw[j]*j%md;
}
for(int i=1;i<=n;++i){
for(int C=c;~C;--C){
int d=0;
for(int j=0;j<=C;++j)
d=(d+(LL)dp[C-j]*(pre[j][B[i]]-pre[j][A[i]-1]+md))%md;
dp[C]=d;
}
}
printf("%d\n",dp[c]);
return 0;
}