Codeforces 577B Modulo Sum:数学 结论【选数之和为m的倍数】

题目链接:http://codeforces.com/problemset/problem/448/C

题意:

  给你n个数字,给定m。

  问你是否能从中选出若干个数字,使得这些数字之和为m的倍数。

题解:

  其实就是要找一些数字,使得之和mod m为0。

  开一个vector,存当前已经能够构成的数字之和mod m之后的值。

  一开始vector为空,然后枚举n个数字a[i],对于每个数字枚举当前vector中的值v[i],将没有出现过的(a[i]+v[i])%m值加入vector中。

  最后判断下vector中有没有0就好。

  然而直接做是O(nm)的过不了。

  这时候就有一个结论:

    当n>m时,一定能够找出一些数字,使得它们之和mod m为0。

  证明:

    令sum[i]为数字a[1 to i]的和mod m后的值。

    显然,一定有一对(i,j)使得sum[i]==sum[j] (i<j)。

    所以有∑ a[i+1 to j] mod m == 0。得证。

  这样当n>m的时候特判一下直接输出,否则再跑上面的做法。

  这样复杂度就成O(m^2)的了。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_M 1005
 6 
 7 using namespace std;
 8 
 9 int n,m;
10 int vis[MAX_M];
11 vector<int> v;
12 
13 int main()
14 {
15     cin>>n>>m;
16     if(n>m)
17     {
18         cout<<"YES"<<endl;
19         return 0;
20     }
21     memset(vis,false,sizeof(vis));
22     int x;
23     for(int i=1;i<=n;i++)
24     {
25         cin>>x;
26         x%=m;
27         for(int j=0,t=v.size();j<t;j++)
28         {
29             int now=(v[j]+x)%m;
30             if(!vis[now])
31             {
32                 v.push_back(now);
33                 vis[now]=true;
34             }
35         }
36         if(!vis[x])
37         {
38             v.push_back(x);
39             vis[x]=true;
40         }
41     }
42     if(vis[0]) cout<<"YES"<<endl;
43     else cout<<"NO"<<endl;
44 }
原文地址:https://www.cnblogs.com/Leohh/p/8251667.html