Codeforces 577B Modulo Sum:數學 結論【選數之和為m的倍數】

Leohh發表於2018-01-09

題目連結: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 }

 

相關文章