一个班级有
a
a
a个男生和
b
b
b个女生,现在这个班级有
k
k
k对男女愿意一起出席毕业典礼,这里注意
k
k
k对男女中可能会有某个男生或女生出现在多个
p
a
i
r
pair
pair中。
你从这
k
k
k对中找出两对,使得这两对中的男生不相同、女生不相同,即一个男生或女生不可能在一个典礼中出现在两对中。
让你求出一共有多少种可能的组合方式。
思路:
枚举这
k
k
k对,假设每对描述为
(
b
i
,
g
i
)
(b_i, g_i)
(bi,gi),那么
k
k
k减去与
b
i
,
g
i
b_i,g_i
bi,gi配对的人的数量
N
(
b
i
,
g
i
)
N_{(b_i,g_i)}
N(bi,gi),就是确定了
(
b
i
,
g
i
)
(b_i,g_i)
(bi,gi)之后可能的情况数。
那么答案
a
n
s
=
∑
i
=
1
k
N
b
i
,
g
i
2
ans=\frac{\sum_{i=1}^kN_{b_i,g_i}}2
ans=2∑i=1kNbi,gi,之所以要除以2是因为每个情况都会被计算两遍,比如对于枚举
(
b
i
,
g
i
)
(b_i,g_i)
(bi,gi)的时候会枚举到
(
b
j
,
g
j
)
(b_j,g_j)
(bj,gj),那么枚举到
(
b
j
,
g
j
)
(b_j,g_j)
(bj,gj)的时候同样也会枚举到
(
b
i
,
g
i
)
(b_i,g_i)
(bi,gi)。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
typedef long long ll;
const int Maxn = 200005;
int in[Maxn][2];
/*
* in[i][0]:第i组的男生的编号
* in[i][1]:第i组的女生的编号
*/
int degree[2][Maxn];
/*
* degree[0][i]:与第i个男生配对的数量
* degree[1][i]:与第i个女生配对的数量
*/
void solve() {
memset(degree, 0, sizeof degree);
int a, b, k;
scanf("%d %d %d", &a, &b, &k);
for (int i = 0; i < k; i++) {
scanf("%d", &in[i][0]);
degree[0][in[i][0]]++;
}
for (int i = 0; i < k; i++) {
scanf("%d", &in[i][1]);
degree[1][in[i][1]]++;
}
ll ans = 0;
for (int i = 0; i < k; i++) {
int u = in[i][0];
int v = in[i][1];
ans += k - degree[0][u] - degree[1][v] + 1;
// +1 是因为当前枚举的pair被减掉两次
}
printf("%lld\n", ans / 2);
}
int main() {
// freopen("/Users/chant/in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}