10J:判断整除

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

一个给定的正整数序列,在每个数之前都插入+号或-号后计算它们的和。比如序列:1、2、4共有8种可能的序列:
(+1) + (+2) + (+4) = 7
(+1) + (+2) + (-4) = -1
(+1) + (-2) + (+4) = 3
(+1) + (-2) + (-4) = -5
(-1) + (+2) + (+4) = 5
(-1) + (+2) + (-4) = -3
(-1) + (-2) + (+4) = 1
(-1) + (-2) + (-4) = -7
所有结果中至少有一个可被整数k整除,我们则称此正整数序列可被k整除。例如上述序列可以被3、5、7整除,而不能被2、4、6、8……整除。注意:0、-3、-6、-9……都可以认为是3的倍数。

输入
输入的第一行包含两个数:N(2 < N < 10000)和k(2 < k< 100),其中N代表一共有N个数,k代表被除数。第二行给出序列中的N个整数,这些整数的取值范围都0到10000之间(可能重复)。
输出
如果此正整数序列可被k整除,则输出YES,否则输出NO。(注意:都是大写字母)
样例输入
3 2
1 2 4
样例输出
NO
 1 #include<iostream>
 2 using namespace std;
 3 int a[10005];
 4 bool f[10005][105]; //前i个数是否模k等于j 
 5 int n, k;
 6 int main(){
 7     cin>>n>>k;
 8     int i, j;
 9     for(i = 0; i < n; i++)
10         cin>>a[i];
11     f[0][0] = true; //0模k肯定等于0    
12     for(i = 1; i <= n; i++){
13         for(j = 0; j < k; j++){
14             f[i][j] = f[i-1][(j-(a[i-1]%k)+k)%k]||f[i-1][(j+(a[i-1]%k))%k];
15         }
16     }
17     if(f[n][0]) cout<<"YES"<<endl;
18     else cout<<"NO"<<endl;
19     return 0;
20 }

备注:https://www.cnblogs.com/Wild-Donkey/p/12219856.html

https://blog.csdn.net/m0_37579232/article/details/84994449

其实好好想想能想出来的。一般涉及到序列肯定有一维状态是前i个数,发现这样是不能转移的,涉及到整除问题,肯定需要知道余数是多少。就增加一维j来表示前i个数模k是否可以为j,这个状态很神奇的没有后效性。f(i,j)就表示序列的前i个数模k是否可以等于j。

考虑处理到第i个数,前i-1个数组成的结果是sum(sum当然是不唯一的,但sum具体是什么不重要,有任何一种满足 可以等于j 的要求就可以),那么第i个数前是正号,前i个数的和就是sum+a[i],那么(sum+a[i])%k如果==j,就要求sum%k==j-a[i]%k, 为了防止数组下标为负,处理成sum%k==(j-a[i]%k+k)%k。如果第i个数前是负号,前i个数的和就是sum-a[i],同理sum%k==(j+a[i]%k)%k。

当然,像链接1 一样,在输入数据时就意识到,只需要关心a[i]%k是多少就行了,直接存的就是余数,就可以在递推公式种少写一个%。

要注意我的数组是从0开始的,所以a[i]实际上是a[i-1].

动规一定要注意的一点:填数组的时候一定要把边界值隔过去!!比如我有一次WA就是因为i从0开始,这样把前面的初始值就给覆盖了。

 

posted @ 2020-06-15 10:53  timeaftertime  阅读(479)  评论(0编辑  收藏  举报