首页 > 代码库 > UVa10036

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])//如果上一次余数存在且为j26             {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 }