UVA 10616 Divisible Group Sums

题意:求从N个数中选出M个数使得他们的和是D的倍数,问这种情况有多少种,因为:

(a+b) % c = ((a % c)+(b%c))%c,所以我们可以先对每个数都%D,那么最后所有数的和就是0,既然已经找到了最终状态,那么为什么我们不反着来呢,就是从0开始递推,我们用dp[i][j]表示选i个和是j的情况个数,注意还有负数的可能

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int num[210],a[210];
long long dp[11][4005];
int N,Q,D,M;

int main(){
    int cas = 1;
    while (scanf("%d%d",&N,&Q) != EOF && N+Q){
        for (int i = 0; i < N; i++)
            scanf("%d",&num[i]);
        printf("SET %d:\n",cas++);
        
        for (int i = 1; i <= Q; i++){
            scanf("%d%d",&D,&M);
            memset(dp,0,sizeof(dp));
            dp[0][0] = 1;
            int sum = 0;
            for (int j = 0; j < N; j++){
                a[j] = (num[j]%D+D)%D;   //还有负数的情况
                sum += a[j];
            }

            long long ans = 0;
            for (int j = 0; j < N; j++)
                for (int k = M-1; k >= 0; k--)
                    for (int t = 0; t <= sum; t++)
                        dp[k+1][t+a[j]] += dp[k][t];
            for (int j = 0; j <= sum; j += D)
                ans += dp[M][j];
            printf("QUERY %d: %lld\n",i,ans);
        }
    }
    return 0;
}




你可能感兴趣的:(UVA 10616 Divisible Group Sums)