- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
- Consider an arbitrary sequence of integers. One can place + or - operators between integers in the sequence, thus deriving different arithmetical expressions that evaluate to different values. Let us, for example, take the sequence: 17, 5, -21, 15. There are eight possible 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 integers divisible by K if + or - operators can be placed between integers in the sequence in such way that resulting value is divisible by K. In the above example, the sequence is divisible by 7 (17+5+-21-15=-14) but is not divisible by 5.
You are to write a program that will determine divisibility of sequence of integers. - 输入
- The first line of the input file contains two integers, N and K (1 <= N <= 10000, 2 <= K <= 100) separated by a space.
The second line contains a sequence of N integers separated by spaces. Each integer is not greater than 10000 by it'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.
- 样例输入
4 7 17 5 -21 15
样例输出
Divisible
题目分析:
题目大意是给你一串数字,第一个数字不能改变,第2~n个数字可以变为相反数。判断这些数字的和是否能被k整除。
因为1 <= N <= 10000, 2 <= K <= 100,因此普通的DFS必定会超时。
解决方案一:DFS 加上一定的剪枝处理
#include <cstdio> #include <cstring> int n,m; bool jud = false; int a[10001]; int v[10001][101]; void dfs(int cur, int x) { if (jud) return; if (x==n-1&&cur%m==0) { jud=1; return; } else if (x==n-1) return; v[x][cur]=1; int plus=(cur+a[x+1])%m; if (x==n-2&&!plus) { jud=1; return; } else if (!v[x+1][plus]) dfs(plus, x+1); int minus=(cur-a[x+1])%m; if (x==n-2&&!minus) { jud=1; return; } else if (!v[x+1][minus]) dfs(minus, x+1); } int main() { scanf("%d %d", &n, &m); for (int i=0; i<n; i++) scanf("%d", &a[i]), a[i]=a[i]%m; dfs(a[0], 0); printf("%s ", jud?"Divisible":"Not divisible"); return 0; }
解决方案二:dp,参照的poj Discuss区的代码
用dp[i-1][j] 表示前i-1行 出现过j 这个数;
#include<stdio.h> #include<iostream> using namespace std; bool dp[10001][101]; long num[10001]; int main() { int n,k; cin>>n>>k; for(int i=1;i<=n;i++) { int a; scanf("%d",&a); num[i]=a%k; } dp[0][0]=true; for(int i=1;i<=n;i++) { for(int j=k-1;j>=0;j--) if(dp[i-1][j]) { dp[i][(j+num[i])%k]=1; dp[i][(k+j-num[i])%k]=1; } } if(dp[n][0]) printf("Divisible "); else printf("Not divisible "); return 0; }
方案三:Discuss中的,算是hash吧,代码比较简洁易懂,并且省空间!!!
#include <iostream> using namespace std; int main() { int a[100],n,k,i; for(i=0;i<100;i++) a[i]=0; cin >> n >> k; int temp; cin >> temp; a[(temp%k + k)%k]=1; for(int i=2;i<=n;i++) { int b[100]; for(int j=0;j<100;j++) b[j]=0; cin >> temp; for(int l=0;l<k;l++)//新输入的数与上轮存在的余数进行加和减运算 { if(a[l]) //就是此处的l被我写成了i,最开始 { b[((l+temp)%k+ k)%k]=1; b[((l-temp)%k+ k)%k]=1; } } for(int j=0;j<k;j++) a[j]=b[j];//某一轮输入结束后,所有存在的余数对应的a数组值取1,别的置0 } if(a[0])cout << "Divisible" << endl;//最后一轮输入结束后,看是否有余数为0,即能整除的结果 else cout << "Not divisible" << endl; return 0; }