lightoj 1125 - Divisible Group Sums 01背包变形

给定一个n,q以及n个数字,代表有q次询问,每次询问一个d,m,选择m个数字(不可重复选)组成集合是d的倍数有多少种方法

q比较小可以先不考虑...

对于一个数字选与不选就构成01背包...选择了多少个数字当做背包体积吧...因为要求方案数,所以不能拿余数当做价值了...

得另外再开一维当做余数,那么选了确定x个数字后余数是多少也要顺便枚举一下吧...

注意,01背包的滚动数组体积那重循环是逆向的,所以选择多少数字那重循环也要逆向来...当然开成三维DP不需要考虑这个事情..

注意爆int..毕竟C(200,10)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
ll dp[12][25];
int a[300];
int main()
{
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        int n,q;
        scanf("%d %d",&n,&q);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        printf("Case %d:\n",cas);
        while(q--)
        {
            int d,m;
            scanf("%d %d",&d,&m);
            memset(dp,0,sizeof(dp));
            dp[0][0]=1LL;
            for(int i=1;i<=n;i++)
            {
                int tmp=a[i]%d;
                for(int j=m;j>=1;j--)
                {
                    for(int k=0;k<d;k++)
                        dp[j][k]+=dp[j-1][(k+2*d-tmp)%d];
                }

            }
            printf("%lld\n",dp[m][0]);
        }
    }
    return 0;
}


你可能感兴趣的:(dp,01背包,lightoj)