http://acm.hust.edu.cn/vjudge/contest/view.action?cid=100977#problem/C
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define PII pair<int,int> using namespace std; typedef long long ll; const int maxn=16000100; const int INF=(1<<29); int n; ll A[maxn],B[maxn],C[maxn],D[maxn]; ll a[maxn],b[maxn]; int cnt_a,cnt_b; int cnt; int bin(int l,int r,ll val) { while(l<r){ int m=(l+r)>>1; //if(val==0) cout<<l<<" "<<r<<" "<<m<<endl; if(b[m]==val) return m; if(b[m]<val) l=m+1; else r=m; } //if(val==0) cout<<"l="<<l<<endl; if(b[l]==val) return l; if(b[r]==val) return r; return -1; } int main() { freopen("in.txt","r",stdin); int T;cin>>T; while(T--){ scanf("%d",&n); REP(i,1,n) scanf("%lld%lld%lld%lld",&A[i],&B[i],&C[i],&D[i]); sort(A+1,A+n+1);sort(B+1,B+n+1);sort(C+1,C+n+1);sort(D+1,D+n+1); cnt_a=cnt_b=0; REP(i,1,n){ REP(j,1,n){ a[++cnt_a]=A[i]+B[j]; b[++cnt_b]=C[i]+D[j]; } } //REP(i,1,cnt_b) cout<<b[i]<<endl; sort(a+1,a+cnt_a+1);sort(b+1,b+cnt_b+1); //REP(i,1,cnt_a) cout<<a[i]<<" ";cout<<endl; //REP(i,1,cnt_b) cout<<b[i]<<" ";cout<<endl; cnt=0; REP(i,1,cnt_a){ int k=bin(1,cnt_b,-a[i]); if(k==-1) continue; //cout<<"ai="<<a[i]<<" k="<<k<<endl; REP(j,k,cnt_b){ if(b[j]==b[k]) cnt++; else break; } for(int j=k-1;j>=1;j--){ if(b[j]==b[k]) cnt++; else break; } } cout<<cnt<<endl; if(T) puts(""); } return 0; } /** 题意: 给4个数集,从每个数集中取出任意一个数,使取出的4个数的和为0,求方案数。每个数集大小n<=4000. 分析: 把前两个数集求和,后两个数集也求和,得到新的大小为n*n数集的两个数集,枚举第一个数集,二分查找第二个数集。 类型: 二分,优化。 注意事项: 二分。。。。l<r的二分方式查找一个数时必须在跳出循环时特判l==r的情况,注意不要爆long long。 坑点: 格式啊格式。。。。 总结: */