1. 程式人生 > >【noip模擬賽 化零】 題解

【noip模擬賽 化零】 題解

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;
    }
}