UVa10036

一 题意描述:

给你N(1<=N<=10,000)个数字,你可以在它们之间的N-1个位置任意放“+”或“-”,放完之后,我们可以计算出表达式的值。 存不存在一种摆放方案使得最后表达式的值可以被K(1<=K<=100)整除。

二 思路分析:

1.基础知识巩固之负数除以正数的余数:

由带余除法,任何一个整数n都可以表示成
n=k*q+r 其中0<=r<q
这里的r就是n除以q的余数
通常记为
n≡r(mod q)
例如
-9=(-2)*5+1
则-9除以5的余数为1。为了保证余数为正,那对于一个负数s(s的绝对值小于k),要求它除以k的余数,那么我们可以用(s+k)%k求得余数。

2.如何引入dp?

我们用f[i][j]=1表示前i个数处理后所得余数为j(0<=J<K),如f[i-1][j]=1;

那么对于第i个数(不妨设为正,任何情况下都取该数的绝对值)而言,有两种选择+或者-

对于+:处理第i个数后的余数为(j+abs(a[i])%k)%k.那么f[i][(j+abs(a[i])%k)%k]=true;

对于:处理第i个数后的余数为(j-abs(a[i])%k+k)%k.那么f[i][(j-abs(a[i])%k+k)%k]=true;

如此往复,直到处理完最后一个数。

下面开始判断:如果f[n-1][0]=true,说明这种情况可以被整除,输出visiable.否则输出disvisable。

三 源码:

 1 #include <iostream>
 2 #include <fstream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 using namespace std;
 7 const int N = 10000 + 10;
 8 const int K = 100 + 10;
 9 bool f[N][K];
10 int a[N];
11 int main()
12 {
13     int n,k;
14     int t;
15     cin>>t;
16     while(t--)
17     {
18         for(int i=0;i<n;i++)
19         cin>>a[i];
20         memset(f,false,sizeof(f));
21         f[0][abs(a[0])%k]=true;
22         for(int i=1;i<n;i++)
23         {
24             for(int j=0;j<k;j++)
25             if(f[i-1][j])//如果上一次余数存在且为j
26             {
27                 f[i][(j+abs(a[i])%k)%k]=true;//(a+b)%k的余数等于( a%k +b%k )%k.
28                 f[i][(j+k-abs(a[i])%k)%k]=true;//此处加k是为了避免余数为负值。
29             }
30         }
31         if(f[n-1][0])  cout<<"Divisible"<<endl;
32         else cout<<"Not divisible"<<endl;
33     }
34     return 0;
35 }
posted @ 2014-07-21 10:29  future_hero  阅读(158)  评论(0编辑  收藏  举报