OpenJudge 3531 判断整除

总时间限制: 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

这道题目讲道理,感觉是一道数学题目,运用逐步取模的思想,减少数组的开销,同时也减小了时间的开销,对于每一个数字只有它本身和它的相反数的情况,所以在输入的时候就先取模k,因为在加法中val[i]和val[i]%k的贡献是一样的,所以在输入的时候就可以直接进行取模。
递推操作如下:ans[i][j] 的i代表的是第i个数,j代表的是加上val[i]的两种情况之后能够算出的和%k之后的结果,那么如果ans[i-1][j] 为真,就代表前i-1个数能够算出来i,这样我们就在这个数字的基础上加上val[i]即可。

#include<iostream>
#include<cstring>
using namespace std;
bool ans[10002][105] = { 0 };
int val[10005][2] = { 0 };
int main()
{
    int num = 0, k = 0;
    scanf("%d%d", &num, &k);
    for (int i = 0; i < num; ++i)
    {
        scanf("%d", &val[i][0]);
        val[i][0] %= k;
        if(val[i][0]) val[i][1] = k - val[i][0];
    }
    memset(ans, 0, sizeof(ans));
    ans[0][val[0][0]] = ans[0][val[0][1]] = true;
    for (int i = 1; i < num; ++i)
        for (int j = 0; j < k; ++j)
            if (ans[i - 1][j])
                ans[i][(j + val[i][0]) % k] = ans[i][(j + val[i][1]) % k] = true;
    if (ans[num - 1][0]) cout << "YES" << endl;
    else cout << "NO" << endl;
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/holmosaint/article/details/73542518