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;
}
}
原文地址:https://www.cnblogs.com/MisakaAzusa/p/9790126.html
时间: 2024-10-08 08:54:26