POJ-2785 4 Values whose Sum is 0
在学习二分法的时候,偶然看到一道非常不错的题目,可以对今后的思维有一定启发~
题目描述:
4 Values whose Sum is 0
Time Limit: 15000MS | Memory Limit: 228000K | |
---|---|---|
Total Submissions: 38477 | Accepted: 11718 | |
Case Time Limit: 5000MS |
Description
The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
Sample Output
5
Hint
Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
Source
试题的中文翻译版本(知道你们懒得看英文O(∩_∩)O):
题目背景
wq突然喜欢上了喜欢寻宝游戏~
题目描述
有一天他发现了4个宝箱,每个宝箱都有n个宝物,并且每个宝物都有一个魔法值,问你现在有多少种情况选出的4个宝物魔法值为0
输入格式
第1行:n 代表宝箱中宝物的个数
第2~n+1行:依次输入4个宝箱中宝物的魔法值,每行4个数
输出格式
输出不同组合的个数。
输入输出样例
输入 #1
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
输出 #1
5
说明/提示
对样例的解释:
分别有{-45, -27, 42, 30}, {26, 30, -10, -46}, {-32, 22, 56, -46},{-32, 30, -75, 77}, {-32, -54, 56, 30}这五种组合
数据规模:
前50%:1<=n<=20,-1000<=a,b,c,d<=1000
后50%:1<=n<=1000,-30000<=a,b,c,d<=30000
注意:数据已在原题基础上减弱,不要求用最难的方法解题,欢迎hack数据
分析:
题目很明确,告诉我们有4列数,要我们从每一列取出一个数字,使得四个数的和为0
思路1:4重for循环,检验4个数的和是否为0,时间复杂度 O ( N 4 ) O(N^4) O(N4)
思路2:3重for循环,枚举前3列的数字,求出所有数和的可能性,这里我们设为A,然后扫一遍第4列,找所有的-A,-A的个数即为ans,时间复杂度 O ( N 3 + N ) O(N^3+N) O(N3+N)
思路3:由于只有4列,所以分成两组 A,B,每组含n^2个元素,即该组两列元素枚举出所有的和。然后A从小到大,B从大到小,找出Ai=(-Bj) 的所有情况,统计一下,就是最后的解。具体方法:开两个变量i,j,i指向s1[0],j指向s2[n*n-1],来一遍双指针法,时间复杂度 O ( N 2 + ( N l o g N ) 2 + N ) O(N^2+(NlogN)^2+N) O(N2+(NlogN)2+N),最终时间复杂度 O ( N 2 l o g N ) O(N^2logN) O(N2logN)
Code:
/*poj-2785*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<set>
#define int long long
typedef long long ll;
#define js ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
int a[4001][4001],s1[4000*4000],s2[4000*4000];
signed main(){
js;
int n;
while(cin>>n){
for(int i=0;i<n;i++){
for(int j=0;j<4;j++){
cin>>a[i][j];
}
}
int l1=0,r1=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
s1[l1++]=a[i][0]+a[j][1];//处理前两列的和
s2[r1++]=a[i][2]+a[j][3];//处理后两列的和
}
}
sort(s1,s1+n*n);
sort(s2,s2+n*n);
int cnt=0;
int l=0,r=n*n-1;//双指针,一个在前,一个在后
for(int i=0;i<n*n;i++){
while(r>=0&&s1[i]+s2[r]>0){//r指针逐渐往前扫,直到s1[i]+s2[r]<=0退出循环
r--;
}
if(r<0) break;//r出界,break
int num=r;//用num临时存储r
while(s1[i]+s2[num]==0&&num>=0){
cnt++;
num--;
}
}
cout<<cnt<<endl;
}
//成功AC
}
目前最可以接受的方法如上所述,时间复杂度基本优化到最低,要注意原题的数据规模达到了 2 e 28 2e28 2e28
希望对你能有所启发😄~