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;
}

 

 

posted @ 2021-03-21 10:52  cono奇犽哒  阅读(158)  评论(0)    收藏  举报