P2946 [USACO09MAR]Cow Frisbee Team S(数学+背包)
题目描述:
老唐最近迷上了飞盘,约翰想和他一起玩,于是打算从他家的 N 头奶牛中选出一支队伍。
每只奶牛的能力为整数,第 i 头奶牛的能力为Ri 。飞盘队的队员数量不能少于 1、大于N。一支队伍的总能力就是所有队员能力的总和。
约翰比较迷信,他的幸运数字是 F ,所以他要求队伍的总能力必须是 F 的倍数。请帮他
算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案对 10^8 取模的值。
思路:要组合成为倍数,首先想到的坑定是要求余,如何dp呢,我们可以考虑dp[i][j],前i个数组合成余数为j的组合数,
于是乎我们就能写出dp转移方程:
dp[i][j]=dp[i-1][j]+dp[i-1][((j-cow[i])+f)%f],cow[i]表示该物品对f的余数,还要加上该物品本身加入组合中的情况
即初始化dp[i][cow[i]]=1;代码中采用了滚动数组优化
2021/5/23更:重做了一遍,代码更简洁了
AC代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 1001000; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 100000000; int n, m; int f[2][1005],pre,now=1; int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &n, &m); f[now][0] = 1; for (int i = 1; i <= n; i++) { swap(now, pre); memcpy(f[now],f[pre], sizeof(f[now])); int t; scanf("%d", &t); for (int j = m - 1; j >= 0; j--) { f[now][(j + t) % m] += f[pre][j]; f[now][(j + t) % m] %= mod; } } cout << f[now][0]-1 << endl; return 0; }