lightoj 1125【01背包变性】

题意:

从n个数里选出m个来,还要使得这m个数之和被d整除。

给一个n和q,再给n个数,再给q个询问,每个询问包含两个数,d,m;
对于每个case输出每个q个询问的可行的方案数。

思路:

每个数只能被取一次
那我直接dp一下,dp[i][j]直接代表前i个物品有j值;
然后j这个值由2^31*200…这就不行了。。。
虽然可以/d
变变变!!!
但是我们可以把余数开一维啊,然后还是前i个物品开一维,但是还有选几个再开一维,那就开三维了。。。
01背包开两维反着更新一下就好了。
dp[i][j]代表选i个有j余数的方案数。
然后考虑C(200,10)DP要开long long
初始化,不选的时候,dp[0][0]=1;ok。

code………………

#include<bits/stdc++.h>
//#include<cstdio>
//#include<math.h>
//#include<string.h>
//#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const double eps=1e-5;
const double pi=acos(-1.0);
const int mod=1e8+7;
const LL INF=0x3f3f3f3f;

const int N=1e2+10;

int a[N*2];
LL dp[12][25];

int main()
{
    int cas=1;
    int n,w,q,d,m;
    int t,x,sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);

        printf("Case %d:\n",cas++);

        for(int k=1;k<=q;k++)
        {
            scanf("%d%d",&d,&m);
            memset(dp,0,sizeof(dp));
            dp[0][0]=1LL;
            for(int i=1;i<=n;i++)
            {
                int temp=a[i]%d;
                for(int j=m;j>=1;j--)
                    for(int x=0;x<d;x++)
                        dp[j][x]+=dp[j-1][(x+2*d-temp)%d];
            }
            printf("%lld\n",dp[m][0]);
        }
    }
    return 0;
}
posted @ 2016-07-25 11:42  see_you_later  阅读(119)  评论(0编辑  收藏  举报