ZOJ2042

/*思路:  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;
}

//真的没了。。。 
//不懂可以探讨,我也刚学(捂脸逃。。。) 
  
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值