题意:给出
N
个班级,每个班级有M个学生,每个学生有个IQ值,问有多少对学生,他们的IQ值加起来>
K
。(两名学生不能来自同一个班级)
思路:升序排序之后,对于每个学生IQ值,可以二分出序列中≥(K+1−IQ)的值的位置,因为不能来自同一个班级,所以要把同班级中
≥(K+1−IQ)
的值减掉,这个也是可以二分的。
坑点:二分的时候注意
left
,
right
和
mid
的关系,搞得不好就陷入了死循环。
http://acm.hdu.edu.cn/showproblem.php?pid=5101
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rep(i,a,b) for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x) memset(a,x,sizeof(a))
#define eps 1e-8
using namespace std;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXE = 2e5;
typedef long long LL;
int T,n,m,k;
int a[1005][105];
int M[1005];
int A[100005];
int num;
void input() {
scanf("%d %d",&n,&k); k++;
num = 1;
rep(i,1,n) {
scanf("%d",&m);
M[i] = m;
rep(j,1,m) { scanf("%d",&a[i][j]) ; A[num++] = a[i][j] ; }
sort(a[i]+1,a[i]+m+1);
}
sort(A+1,A+num);
}
int erfen1(int value) {
if(value > A[num-1]) return 0;
int left = 1 , right = num - 1;
int mid ;
while(left < right) {
mid = (left + right) >> 1;
if(A[mid] < value)left = mid + 1;
else right = mid ;
}
return num - left;
}
int erfen2(int value,int ia) {
if(value > a[ia][M[ia]]) return 0;
int left = 1 , right = M[ia];
int mid ;
while(left < right) {
mid = (left + right) >> 1;
if(a[ia][mid] < value)left = mid + 1 ;
else right = mid ;
}
return M[ia] + 1 - left;
}
void solve() {
int tmp1,tmp2;
long long ans = 0;
rep(i,1,n) {
rep(j,1,M[i]) {
tmp2 = erfen1(k-a[i][j]);
tmp1 = erfen2(k-a[i][j],i);
ans += (LL)(tmp2 - tmp1);
}
}
printf("%I64d\n",ans/2);
}
int main(void) {
scanf("%d",&T);
while(T--) {
input();
solve();
}
return 0;
}