整体二分

时间限制:C/C++ 15秒,其他语言30秒
空间限制:C/C++ 228000K,其他语言456000K
64bit IO Format: %lld

题目描述

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 .

输入描述:

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 2 28 ) that belong respectively to A, B, C and D .

输出描述:

For each input file, your program has to write the number quadruplets whose sum is zero.
示例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

输出

复制
5

备注:

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).

解题思路

很明显最简单思路就是四重枚举,时间复杂度爆炸,如果排序最后一行,枚举前3行,最后二分,时间复杂度也爆炸了。
那么怎么再优化呢!一个比较经典的模型整体二分。把这个4个排列对半一砍,把左边出现的全部组合保存起来,再去枚举右边可能出现的组合去二分前面和他组合是负数的方法数累加即可。

#pragma GCC target("avx,sse2,sse3,sse4,popcnt")
#pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math")
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void write(ll x) { if (!x) { putchar('0'); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline int lowbit(int x) { return x & (-x); }

const int N = 4e3 + 7;
int a[N], b[N], c[N], d[N];
vector<int> v;

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read(), b[i] = read(), c[i] = read(), d[i] = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            v.push_back(a[i] + b[j]);
    sort(v.begin(), v.end());
    ll ans = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) {
            int x = -(c[i] + d[j]);
            ans += upper_bound(v.begin(), v.end(), x) - lower_bound(v.begin(), v.end(), x);
        }
    write(ans);
    return 0;
}