【问题描述】
Consider an arbitrary sequence ofintegers. One can place + or - operators between integers in the sequence, thusderiving different arithmetical expressions that evaluate to different values.Let us, for example, take the sequence: 17, 5, -21, 15. There are eightpossible expressions:
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
We call the sequence of integersdivisible by K if + or - operators can be placed between integers in thesequence in such way that resulting value is divisible by K. In the aboveexample, the sequence is divisible by 7 (17+5+-21-15=-14) but is not divisibleby 5.
You are to write a program that willdetermine divisibility of sequence of integers.
译题:
给出N个数,你可以在这N个数中任意地添加+号或-号,求出能不能使算出的结果被K整除。可以则打印“Divisible”,否则打印“Not divisible”
(1 <= N <= 10000, 2 <= K<= 100)
下面是一个例子:
有4个数,分别是17 5 -21 15
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
有8种添法,其中第二种求出的-14能被7整除。
【输入文件】
The first line of the input containstwo integers, N and K (1 <= N <= 10000, 2 <= K <= 100) separated bya space.
The second line contains a sequenceof N integers separated by spaces. Each integer is not greater than 10000 byit's absolute value.
注意第一个数是测试数据的组数,多组测试数据一起测。。
【输出文件】
Write to the output file the word"Divisible" if given sequence of integers is divisible by K or"Not divisible" if it's not.
The first line of a multiple input isan integer N, then a blank line followed by N input blocks. Each input block isin the format indicated in the problem description. There is a blank linebetween input blocks.
The output format consists of Noutput blocks. There is a blank line between output blocks.
注意:输出每组结果之间有空格,最后一行无空格,格式不对不能AC,我就是因为格式不对调了一上午。。。。
【输入样例】
2
4 7
17 5 -21 15
4 5
17 5 -21 15
【输出样例】
Divisible
Not divisible
【问题分析】
看到题目第一个反映就是枚举中间添的运算符,算出值在MOD K如果有一个值MOD K=0则输出“Divisible”。
时间复杂度是O(2N-1)。
但是题目给出的数据量很大,这样做效率太低了。
因为题目涉及MOD运算,要想简化问题就需要知道一些基本的MOD运算性质:
A*B mod C=(A mod C*B mod C) mod C
(A+B) mod C=(A mod C+B mod C) mod C
有了这个性质,我们就可以把累加后求余转化成求余后累加(我们把减法看作加负数以后分析只说加法)再求余。这样我们的读入数据就控制在了1-K到K-1的范围内了。
我们要判断的就是
所有结果的累加和 MOD K 是否为0。简记为:
(A+B)mod K=0 or (A+B) mod K<>0
如果我们按数的个数划分阶段,前N-1个数的运算结果 MOD K看做A,第N个数看作B就OK了。
于是我们想到了这样的状态:opt[i,j]表示前i个数是否可以得到余数为J的结果。
那么状态转移方程就是
opt[i,(j-a[i] mod k )modk]=opt[i-1,j] (opt[i-1,j]=true);
opt[i,(j+a[i] mod k) modk]=opt[i-1,j] (opt[i-1,j]=true);
如果opt[n,0]=true就输出‘Divisible’
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; int n, k; int a[10001]; bool rem[10001][101]; int main() { int t; scanf("%d",&t); while(t--) { int i, j; scanf("%d%d",&n,&k); for(i = 0; i < n; i++) { scanf("%d",&a[i]); a[i] = (a[i] % k + k) % k; //注意有负数 } memset(rem,0,sizeof(rem)); rem[0][a[0]] = true; for(i = 1; i < n; i++) for(j = 0; j < k; j++) if(rem[i-1][j]) rem[i][(j+a[i]+k)%k] = rem[i][(j-a[i]+k)%k] = true; if(rem[n-1][0]) printf("Divisible\n"); else printf("Not divisible\n"); if(t) printf("\n"); //这题的输出格式要求比较严格,注意了。 } return 0; }