题意:
给你n个题,每个题都有一个主题和一个难度,输入保证同一个主题下不会有相同难度的题出现,现选择三个题组成一个题集,问你满足以下至少一个条件的选择有多少种:1.所选择的三个题目主题互不相同。2.所选择的三个题难度互不相同。
思路:
直接算出所有方案数的难度过大,于是走反面,用总的选择数-非法的选择数。
对于此题的输入,我们可以建立邻接矩阵,并将每一种难度的题的数目装入桶中。
遍历所有的问题,对于问题
a
(
i
,
j
)
a(i,j)
a(i,j),i表示主题,j表示难度,一定包含问题a的非法组合的数目为:
(
i
主
题
的
问
题
数
目
−
1
)
∗
(
j
难
度
的
问
题
数
目
−
1
)
(i主题的问题数目-1)*(j难度的问题数目-1)
(i主题的问题数目−1)∗(j难度的问题数目−1)
用
C
n
3
C_n^3
Cn3减去这些非法组合就是答案。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll vis[200010];
ll d[200010];
vector<ll>a[200010];
int main()
{
int t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
for(int i = 1; i <= n; i++)
{
ll num,leve;
scanf("%lld%lld",&num,&leve);
a[num].push_back(leve);
vis[leve]++;
}
int cnt = 0;
ll ans = n*(n-1)*(n-2)/6;
for(int i = 1; i <= n; i++)
{
if(a[i].size())d[++cnt] = i;
}
ll k = 0;
for(int i = 1; i <= cnt; i++)
{
k = 0;
for(int j = 0; j < a[d[i]].size(); j++)
{
k += (vis[a[d[i]][j]]-1)*(a[d[i]].size()-1);
}
ans-=k;
}
printf("%lld\n",ans);
for(int i = 1; i <= n; i++)a[i].clear(),d[i] = 0,vis[i] = 0;
}
}