ZOJ2042

来源:互联网 发布:centos 编译安装git 编辑:程序博客网 时间:2024/06/06 07:51
/*思路:  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=3dp[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 = 1a[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 = 2a[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");elseprintf("Not divisible\n");if(r)printf("\n");}return 0;}//真的没了。。。 //不懂可以探讨,我也刚学(捂脸逃。。。) 
原创粉丝点击