1. 程式人生 > >【Henu ACM Round#18 B】Modulo Sum

【Henu ACM Round#18 B】Modulo Sum

ret color cout down .com for endif force pac

【鏈接】 我是鏈接,點我呀:)
【題意】


在這裏輸入題意

【題解】


m比較小
<=1000

a[i]直接看成a[i]%m就可以了。

有n個0..999之間的整數。。

如果有一個0那麽就直接輸出Yes.

否則要用那些數字湊0

則用cnt[0..999]記錄每個數字出現的個數。
即n個物品,每個物品cnt[i]個。
然後湊和為0

->多重背包。

但每個物品的數量可能很多。
所以加一個二進制優化就好了。
把每個物品的數量轉化成二進制。

轉換成01背包的問題。
(物品的數目大概在1000*log2(1e6)的樣子

然後容量是1000.

這時候就可以做了。

另解
如果n>m的話。
前綴和數組中肯定有sum[i]%m和sum[j]%m相同。

(抽屜原理,每個數字在0..m-1之間,然後有m+1個數字的話,顯然不可能每個數字都相同。
則i+1..j之間的和就是m的倍數了。
所以直接輸出YES.
否則做一個O(M^2)的背包就好。

【代碼】

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int M = 1e3+10;

bool f[2][M];
int a[M],n,m;
vector<int> v;

int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    #ifdef LOCAL_DEFINE
freopen("rush.txt","r",stdin); #endif cin >> n >> m; for (int i = 1;i <= n;i++) { int x;cin >>x;x%=m; a[x]++; } if (a[0]>0){ cout<<"YES"<<endl; return 0; } for
(int i = 1;i < m;i++) if (a[i]>0){ int temp = 1; while (a[i]>=temp){ v.push_back((1LL*temp*i)%m); a[i]-=temp; temp*=2; } if (a[i]>0) v.push_back((1LL*a[i]*i)%m); } if (!v.empty()){ f[0][v[0]] = 1; if (v[0]==0) return cout<<"YES"<<endl,0; for (int i = 1;i <(int)v.size();i++){ for (int j = 0;j < m;j++) f[i&1][j] = 0; for (int j = 1;j <= m-1;j++) if (f[(i&1)^1][j]){ int k = (j+v[i])%m; f[i&1][j] = 1; f[i&1][k] = 1; } f[i&1][v[i]] = 1; if (f[i&1][0]) return cout<<"YES"<<endl,0; } } cout<<"NO"<<endl; return 0; }

【Henu ACM Round#18 B】Modulo Sum