【Henu ACM Round#18 B】Modulo Sum
阿新 • • 發佈:2018-01-29
ret color cout down .com for endif force pac
(抽屜原理,每個數字在0..m-1之間,然後有m+1個數字的話,顯然不可能每個數字都相同。
則i+1..j之間的和就是m的倍數了。
所以直接輸出YES.
否則做一個O(M^2)的背包就好。
【鏈接】 我是鏈接,點我呀:)
【題意】
在這裏輸入題意
【題解】
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相同。
則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