[CodeForces 577B]Modulo Sum[实现][数学]

来源:互联网 发布:mac上的svn管理工具 编辑:程序博客网 时间:2024/06/05 15:28

题目链接:[CodeForces 577B]Modulo Sum[实现][数学]

题意分析:

给出n个数,再给出一个数m。问给出的n个数中,任意组合,是否存在组合出来和能被m整除。

解题思路:

进一步说:题目就是问:在所有这些数能得到的组合中,是否存在和使得其被m整除。显然,这些组合出来的和取余后不大于m,这里面存在着大量重复。所以我们可以用一个数组标记这个和是否出现过,如果没出现就放入vector数组,然后每次更新这个vector数组。

整个复杂度1e9。不过不会到达,原因是n>m时,答案一定存在,所以总复杂度应该是m^2。

具体理由如下:

正如前面所说,取余之后的数不大于m,当存在n>m个数时,考虑从第一个数字开始的连续和,不断地去与m取余,必定有一次会出现取余后的结果之前出现过。因为:假设每次新增一个数之后的连续和取余之后的数都是新的,那么至多m次之后就会出现之前出现过的连续和,设第一次出现的连续区间为[0,first]第二次出现的区间为[0,second]。那么必然有:(sum(0,first) + sum(first,second))%m = sum(0,first) % m + sum(first, second) %m = sum(0, second)。

因为sum(0,first) == sum(0, second), 所以sum(first,second) % m = 0。好啦,证毕。

个人感受:

弱渣昨天那场跪惨了。感觉能力还是不足。数学是会呼吸的痛。

具体代码如下:

#include<iostream>#include<cstdio>#include<algorithm>#include<queue>using namespace std;const int MAXN = 1e3 + 111;int a, n, m, sum[MAXN];bool flag = 0, vis[MAXN];int main(){    scanf("%d%d", &n, &m);    vector<int> sum;    for (int i = 0; i < n; ++i)    {        scanf("%d", &a);        a %= m;        int len = sum.size();        for (int j = 0; j < len; ++j) // 更新vecotr数组        {            int newSum = (sum[j] + a) % m;            if (newSum == 0)            {                flag = 1;                goto ed;            }            if (!vis[newSum])            {                sum.push_back(newSum);                vis[newSum] = 1;            }        }        if (!vis[a]) // 别忘了要把这个数本身放进去        {            if (a == 0)            {                flag = 1;                break;            }            sum.push_back(a);            vis[a] = 1;        }    }ed:    if (flag) printf("YES\n");    else printf("NO\n");    return 0;}


0 0
原创粉丝点击