hdu 5464 DP 同余

来源:互联网 发布:淘宝店铺隐形降权查询 编辑:程序博客网 时间:2024/05/29 15:30

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5464

对于初学者,难的不是能不能想到DP,而是能不能想到 倍数问题 用 取模来解决(个人观点)

对输入的 a[i] 都a[i] %= p.

然后动态规划  

dp[i][j] 表示前i个数中选择,总和%p  为 j 的个数。

 dp[i][j] = dp[i-1][j] + dp[i-1][(j-a[i])%p],  dp[i-1][j]表示没选第i个数的情况,dp[i-1][(j-a[i])%p] 表示 选了第i个数的情况。


上面的解释为了方便理解没有考虑 负数的情况,具体负数的情况见代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#define MS(x,y) memset(x,y,sizeof(x))using namespace std;void fre(){freopen("t.txt","r",stdin);}typedef long long LL;typedef unsigned long long ULL;const int mod = 1e9+7;int a[1005],dp[1005][1005];int main(){ //   fre();    int i,j,t,n,p;    scanf("%d",&t);    while(t--)    {        MS(dp,0);        scanf("%d%d",&n,&p);        for(i = 0; i < n; ++i)        {            scanf("%d",&a[i]);            a[i] %= p;            if(a[i]<0) a[i]+=p;        }        dp[0][0] = 1;        dp[0][a[0]] += 1;        for(i = 1; i < n; ++i)        {            for(j = 0; j < p; ++j)            {                int x = (j - a[i] + p) % p;                dp[i][j] = (dp[i-1][j] + dp[i-1][x])%mod;            }        }        printf("%d\n",dp[n-1][0]);    }    return 0;}

1 0
原创粉丝点击