给我们 n 个数的,我们可以从中选择任意个数把这些数的值加起来,要求这个数是 m 的倍数,问我们组成的数字是的倍数是 m 的方案数,
注意一个也不选组成的数是 0 也算一种合法方案。
n <=1000, p<=1000.
思路
一看到组成的数是 m 的倍数就要明白我们可以在 dp 的状态中用一位 去枚举余数,
其实 dp 方程很容易就可以猜出来:dp [i][j] 表示前 i 个数从中选择一些数字的和是 % m 的余数是 j 的方案数,那么答案就是 dp [n][0] 了 ,
那么状态转移方程为:
如果第 i 个数我们不选择:dp [i][j] += dp [i - 1][j]
如果选择第 i 个数:dp [i][(j + a [i]) % m] += dp [i][j]
代码
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definescscanf#defineprprintf#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#definePirpair<int,int>#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =1005;constint mod =1e9+7;int n, p, a[N];int dp[N][N];intmain(){int T;sc("%d",&T);while(T --){sc("%d %d",&n,&p);for(int i =1; i <= n; i ++)sc("%d",&a[i]);memset(dp,0,sizeof dp);
dp[0][0]=1;for(int i =1; i <= n; i ++){for(int j =0; j < p; j ++){if(dp[i -1][j]==0)continue;int k =(j + a[i]% p + p)% p;
dp[i][k]=(dp[i][k]+ dp[i -1][j])% mod;
dp[i][j]=(dp[i][j]+ dp[i -1][j])% mod;}}pr("%d\n", dp[n][0]);}return0;}