题意:
给你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;
}
}