dp百题进度条[2/100]算法
题目连接dom
题目描述
对于任意一个整数数列,咱们能够在每两个整数中间任意放一个符号'+'或'-',这样就能够构成一个表达式,也就能够计算出表达式的值。好比,如今有一个整数数列:17,5,-21,-15,那么就能够构造出8个表达式:spa
17+5+(-21)+15=16 17+5+(-21)-15=-14 17+5-(-21)+15=58 17+5-(-21)-15=28 17-5+(-21)+15=6 17-5+(-21)-15=-24 17-5-(-21)+15=48 17-5-(-21)-15=18
对于一个整数数列来讲,咱们能经过如上的方法构造出不一样的表达式,从而获得不一样的数值,若是该数值可以被k整除的话,那么咱们就称该数列能被k整除。 在上面的例子中,该数列能被7整除(17+5+(-21)-15=--14),但不能被5整除。如今你的任务是,判断某个数列是否能被某数整除。code
输入格式
第一行是一个整数m,表示有m个子任务。接下来就是m个子任务的描述。 每一个子任务有两行。第一行是两个整数n和k(1<=n<=10000, 2<=k<=100),n和k中间有一个空格。n 表示数列中整数的个数;k就是须要你判断的这个数列是否能被k 整除。第二行是数列的n个整数,整数间用空格隔开,每一个数的绝对值都不超过10000。get
输出格式
输出文件应有m 行,依次对应输入文件中的m 个子任务,若数列能被k 整除则输出 "Divisible",不然输出 "Not divisible" ,行首行末应没有空格。string
输入输出样例
输入 #1
2
4 7
17 5 -21 15
4 5
17 5 -21 15
输出 #1
Divisible
Not divisibleio
思路一:正常的dp
0/1背包,本身看就好惹方法
#include<cstdio> #include<cstring> using namespace std; const int MAXN = 10005; int x,k,n; bool dp[MAXN][1005]; inline int mod(int x){ x %= k; if (x < 0) x += k; return x; } int main(){ int t; scanf("%d",&t); while (t--){ scanf("%d %d",&n,&k); memset(dp,false,sizeof(dp)); scanf("%d",&x); dp[0][mod(x)] = true; dp[0][mod(-x)] = true; for (register int i = 1 ; i < n ; i++){ scanf("%d",&x); x = mod(x); for (register int j = 0 ; j < k ; j++){ dp[i][j] = dp[i - 1][mod(j - x)] | dp[i - 1][mod(j + x)]; } } if (t == 0){ if (dp[n - 1][0] == true) printf("Divisible"); else printf("Not divisible"); } else{ if (dp[n - 1][0] == true) printf("Divisible\n"); else printf("Not divisible\n"); } } return 0; }
思路二(我很钦佩的一种作法):
随机化算法,彻底看脸di
#include<cstdio> #include<cstdlib> using namespace std; int a[10001]; int i,n,T,k,randomm,ans; int main( ) { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); for(i=1;i<=n;i++) scanf("%d",&a[i]); int tot=500,flag=0; while(tot) { tot--; ans=0; for(i=1;i<=n;i++) { randomm=rand(); if(randomm%2) ans+=a[i]; else ans-=a[i]; } if(ans%k==0) { printf("Divisible\n"); flag=1; break; } } if(!flag) printf("Not divisible\n"); } return 0; }