Divisible Group Sums
分类:dp
1.题意概述
- 给你
n
个数,要你从中挑选
m 个,使得它们的和能够被 D 整除。
2.解题思路
- 标准的动态规划,用
dp[i][j][k][mod] 表示前 i 个数选了j 个,除数为 k ,余数为mod 的情况,那么下一步选择就是选或者不选,实际上这就是一个01背包问题,转移方程:
- 选这个数: dp[i][j][k][(a[j][k]+l)%k] += dp[i−1][j−1][k][l]
- 不选这个数: dp[i][j][k][l] += dp[i−1][j][k][l]
3.AC代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 50010
#define N 222
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
ll dp[11][22];
int a[N], fac[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int t, n, q, kase = 0;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &q);
printf("Case %d:\n", ++kase);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
while (q--)
{
int d, m;
scanf("%d%d", &d, &m);
for (int i = 1; i <= n; i++)
fac[i] = (a[i] % d + d) % d;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = m; j > 0; j--)
for (int k = 0; k < d; k++)
dp[j][(k + fac[i]) % d] += dp[j - 1][k];
printf("%lld\n", dp[m][0]);
}
}
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}