【noip模擬賽 化零】 題解
阿新 • • 發佈:2018-11-12
Describe
有5個集合,每個集合N個元素,從每個集合選出一個數,共5個,問是否可以使和為0。
IN put:
第一行一個整數 N,表示集合的大小。
接下來五行每行 N個整數,表示這五個集合內的元素。
OUT put:
如果能找到符合條件的五個數,則輸出“YES”,否則輸出“NO”。
example:
in
3
1 -2 9
-1 2 1
-3 5 1
-1 7 6
-4 -1 -7
out
YES
資料範圍:
N<=20 30%
N<=200 100%
題解:
考慮 N <= 20 直接N^5暴力
對於 N > 20 考慮一種賭博式的想法
如果有合法解的話,不妨設在前兩個集合和後三個集合存在相反數
這樣我們可以預先處理出N^2 和 N^3 的方案數,再進行組合,看是否有相反數
這時候我們先排序再套個lower_bound就ok了
最差在沒有解大概跑了1.11s
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; const int maxn = 210; ll a[maxn], b[maxn], c[maxn], d[maxn], e[maxn], n; ll ans1[41000], ans2[8000100], cnt1 = 0, cnt2 = 0; inline ll read() { ll k=0,f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-')f=-1; c=getchar(); } while(isdigit(c)) { k=(k<<1)+(k<<3)+c-48; c=getchar(); } return k*f; } int main() { n = read(); for(int i = 1; i <= n; i++) a[i] = read(); for(int i = 1; i <= n; i++) b[i] = read(); for(int i = 1; i <= n; i++) c[i] = read(); for(int i = 1; i <= n; i++) d[i] = read(); for(int i = 1; i <= n; i++) e[i] = read(); if(n <= 25) { for(int v = 1; v <= n; v++) for(int w = 1; w <= n; w++) for(int x = n; x >= 1; x--) for(int y = n; y >= 1; y--) for(int z = n; z >= 1; z--) { if(a[v] + b[w] + c[x] + d[y] + e[z] == 0) { cout<<"YES"<<endl; return 0; } } cout<<"NO"<<endl; return 0; } else { for(int v = 1; v <= n; v++) for(int w = 1; w <= n; w++) ans1[++cnt1] = a[v]+b[w]; for(int x = 1; x <= n; x++) for(int y = 1; y <= n; y++) for(int z = 1; z <= n; z++) ans2[++cnt2] = -1*(c[x]+d[y]+e[z]); sort(ans1+1, ans1+1+cnt1); for(int i = 1; i <= cnt2; i++) { int now = lower_bound(ans1+1, ans1+1+cnt1, ans2[i])-ans1; if(ans1[now] == ans2[i]) { cout<<"YES"<<endl; return 0; } } cout<<"NO"<<endl; return 0; } }