紫书上叫中途相遇法,还有一个名字感觉更加妥帖一点,叫:折半枚举。 有时候,当问题的规模较大时,无法枚举所有元素的组合,但能够枚举一半的元素组合,此时,将问题拆成两半后分别枚举,再合并他们的结果这一方法往往非常有效。
两重循环加二分,总复杂度为n^2logn
这里值得一提的是对集合CD的存储方式,我是用了一个有序数组,也可以用其他方式。
#include<bits/stdc++.h> using namespace std; const int max_n =4005; int n,T; long long A[max_n],B[max_n],C[max_n],D[max_n],CD[max_n*max_n]; void solve(){ for(int i=0;i<n;i++) for(int j=0;j<n;j++) CD[i*n+j] = C[i] + D[j]; sort(CD,CD+n*n); long long res = 0; for(int i=0;i<n;i++) for(int j=0;j<n;j++){ int cd = -(A[i]+B[j]); res+=upper_bound(CD,CD+n*n,cd) - lower_bound(CD,CD+n*n,cd); } printf("%lld\n",res); } int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%lld",&A[i]); scanf("%lld",&B[i]); scanf("%lld",&C[i]); scanf("%lld",&D[i]); } solve(); if(T) printf("\n"); } return 0; }
时间: 2024-10-11 23:12:52