【u028】数列的整除性

来源:互联网 发布:淘宝配送地址填写海外 编辑:程序博客网 时间:2024/06/05 09:34

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式,也就可以计算出表达式的值。比如,现在有一个整数数列:17,5,-2,-15,那么就可以构造出8个表达式: 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整除。现在你的任务是,判断某个数列是否能被某数整除。


【输入格式】

第一行是一个整数m,表示有m个子任务。接下来就是m个子任务的描述。 每个子任务有两行。第一行是两个整数n和k(1<=n<=10000, 2<=k<=100),n和k中间有一个空格。n 表示数列中整数的个数;k就是需要你判断的这个数列是否能被k 整除。第二行是数列的n个整数,整数间用空格隔开,每个数的绝对值都不超过10000。

【输出格式】

输出文件应有m 行,依次对应输入文件中的m 个子任务,若数列能被k 整除则输出 "Divisible",否则输出 "Not divisible" ,行首行末应没有空格。

【数据规模】

Sample Input1

24 717 5 -21 154 517 5 -21 15

Sample Output1

DivisibleNot divisible
【题解】
这是一道动态规划的问题。
设f[i][j]表示前i个数余数为j的情况是否出现
f[i+1][(j+a[i+1])%k] = f[i+1][(j+a[i+1])%k] || f[i][j];
f[i+1][|j-a[i+1]|%k] = f[i+1][|j-a[i+1]|%k] || f[i][j];
然后一开始,如果输入的n个数字,出现负数,就直接取相反数改为正数就好。
这里用到了同余率(反正就是(a+b-c)  % k == ((a+b) %k - c)%k 这样。因为我的题A掉了。所以这个等式应该是成立的。。
然后对于每一个数字,只有加或减两张情况。
然后之所以用余数来表示,是因为余数这个变量的k值不大,最大只有100.是适合用来作为状态的。
如果f[n][0]为true,则表示这个数列能够被整除。
【代码】
#include <cstdio>#include <cstring>bool f[10001][101];int a[10001];int m, n,k;int main(){scanf("%d", &m); //有m组数据for (int i = 1; i <= m; i++){memset(f, false, sizeof(f));scanf("%d%d", &n, &k);for (int i = 1; i <= n; i++){scanf("%d", &a[i]); //如果是负数就直接改为正数就好。if (a[i] < 0)a[i] = -a[i];}f[1][a[1] % k] = true;//第一个数前的符号是不能改的。for (int i = 2;i <= n;i++)for (int j = 0;j <= k;j++)//其他数字的符号则可以改。if (f[i - 1][j]){int temp = j + a[i];//加法的话temp不会出现负数所以不用加绝对值。temp = (temp % k);f[i][temp] = true;temp = j - a[i];//减法就可能为负数了。要注意。if (temp < 0)temp = -temp;temp = (temp % k);f[i][temp] = true;//从前一个状态推到当前的状态。}if (f[n][0])//如果前n个数的余数为0.就表示这个数列能够被整除。printf("Divisible\n");elseprintf("Not divisible\n");}return 0;}


0 0
原创粉丝点击