/*思路: dp[i][j]=dp[i-1][j-a[i]]
dp[i][j]=dp[i-1][j+a[i]]
dp[i][j]表示 取前i个数 相加 或 相减 时 对k取余为j
sum(a[i])%k = sum(a[i]%k)%k
以 17 5 -21 15 为例
dp[0][0] = 1;
dp[1][(0+17)%7] = a[1][3] // 第一个数加起来对7取余为3 (0+17)%7=3
dp[1][(0-17)%7 + 7] = a[1][4] // 第一个数加起来对7取余为4 (0-17)%7 + 7 = 4;
加7是为了把负号消去
此时第一个数对7取余可能是3或4;
计算第二个数,
第一个数取余为3时
a[2][(3+5)%7] = a[2][1]; 前两个数加起来对7取余为1 (17 % 7 + 5) % 7 = 1
a[2][(3-5)%7] = a[2][5]; 前两个数加起来对7取余为5 (17 % 7 - 5) % 7 = 5
第一个数取余为4时
a[2][(5+4)%7] = a[2][2]; 前两个数加起来对7取余为2 (-17 % 7 + 5) % 7 = 2
a[2][(4-5)%7] = a[2][6]; 前两个数加起来对7取余为6 (-17 % 7 - 5) % 7 = 6
以此类推。。。。。。 往下看还有 *^_^*
*/
#include<stdio.h>
#include<string.h>
int num[11000];
int dp[11000][110];
int n;
int k;
int main()
{
int r,i,j;
scanf("%d",&r);
while(r--)
{
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
scanf("%d %d",&n,&k);
for(i=1; i<=n; i++)
scanf("%d",&num[i]);
dp[0][0] = 1;
for(i=1; i<=n; i++)
{
for(j=0; j<k; j++) //j是对k取余的结果,不会大于k
{
if(dp[i-1][j])
{
dp[i][(((j+num[i])%k)+k)%k] = 1;
dp[i][(((j-num[i])%k)+k)%k] = 1;
}
}
}
/*j代表余数,dp[i][j]的意思就是前i个数相加或相减,余数为j;
要计算状态转移方程,首先要确保a[i-1][j]存在,也就是前i个数有余数
这里令 dp[i][(((j+num[i])%k)+k)%k] = 1; 有标记的意思
此时再把前i项计算的余数与第i个数加起来 ,继续计算
j表示的不再是行列,而是一个具体的数值,只要表示出前i个数经过加减后的
的余数,若j为0代表前i个数经过运算可以整除K
没了。。。。。。*/
if(dp[n][0])
printf("Divisible\n");
else
printf("Not divisible\n");
if(r)
printf("\n");
}
return 0;
}
//真的没了。。。
//不懂可以探讨,我也刚学(捂脸逃。。。)
01-15
232
09-14
09-14