A 组队参赛
|
问题描述
一年一度的信息学竞赛NK校赛即将开始,何老板在组织安排报名工作。
南开信竞队分为小学、初中、高中三个梯队:
小学梯队有N个队员,年龄分别是A1,A2,……,AN
初中梯队有N个队员,年龄分别是B1,B2,……,BN
高中梯队有N个队员,年龄分别是C1,C2,……,CN
比赛是组队参赛,三人一队,要求每只队伍里面必须要有小学、初中和高中各一人。同时,要求每个队中,小学队员的年龄<初中队员的年龄<高中队员的年龄。
何老板想知道,总共可能的组队方案有多少种?请你帮他算一算。两种组队方案中,至少存在一个不相同的同学,即被认为是不同方案。
输入格式
第一行,一个整数N
接下来三行,每行N个整数,分别表示每个梯队的队员年龄:
输出格式
一个整数,表示不同的组队方案总数。
样例输入 1
2
1 5
2 4
3 6
样例输出 1
3
样例输入 2
3
1 1 1
2 2 2
3 3 3
样例输出 2
27
样例输入 3
6
3 14 159 2 6 53
58 9 79 323 84 6
2643 383 2 79 50 288
样例输出 3
87
提示
1 ≤ N ≤ 105
1 ≤ Ai ≤ 109(1 ≤ i ≤ N)
1 ≤ Bi ≤ 109(1 ≤ i ≤ N)
1 ≤ Ci ≤ 109(1 ≤ i ≤ N)
【分析】
首先观察题意,很简单我们可以知道是要我们找到所有递减的三元数组的个数。有很多方法都可以做到,但要小心,一不小心就会O(n2)。我们先对A,B,C三个数组从小到大排序,重点放在B数组上。因为sort的关系,自然可以用lower_bound、upper_bound处理A,C中的可行选择个数,之后用乘法原理即可解答。
【标程】
1 #include<cstdio> 2 #include<algorithm> 3 #define R register int 4 #define ll long long 5 #define For(i, s, n) for (R i = s; i <= n; ++ i) 6 #define maxn 100005 7 using namespace std; 8 int n; 9 ll ans; 10 int A[maxn], B[maxn], C[maxn]; 11 inline char nc(){ 12 static char buf[100000],*p1 = buf, *p2 = buf; 13 return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++; 14 } 15 inline int read(){ 16 char ch = nc(); 17 int sum = 0; 18 while (!(ch >= '0' && ch <= '9'))ch = nc(); 19 while (ch >= '0' && ch <= '9')sum = sum * 10 + ch - 48, ch = nc(); 20 return sum; 21 } 22 void ini() { 23 scanf("%d", &n); 24 For (i, 1, n)A[i] = read(); 25 For (i, 1, n)B[i] = read(); 26 For (i, 1, n)C[i] = read(); 27 sort(A + 1, A + n + 1); 28 sort(B + 1, B + n + 1); 29 sort(C + 1, C + n + 1); 30 } 31 void solve() { 32 For (i, 1, n) { 33 ll p = lower_bound(A + 1, A + n + 1, B[i]) - A - 1; // lower_bound是查找从左起第一个大于等于的位置下标,p减1是因为题目要求严格小于 34 ll q = upper_bound(C + 1, C + n + 1, B[i]) - C - 1; // upper_bound是查找从左起第一个大于等于的位置下标 35 ans += p * (n - q); // 乘法原理 36 } 37 printf("%lld", ans); 38 } 39 int main() { 40 ini(); 41 solve(); 42 return 0; 43 }