CF1598D Training Session题解
题意
给你一个长度为\(n\)的二元组序列,这个序列中任取三个元素,这三个元素组成的三元组是*ao的,当且仅当这个三元组至少满足如下两个条件中的一个:
1.三元组中三个元素的第一个元素互不相同
2.三元组中三个元素的第二个元素互不相同
现在请你求出,你有多少种方法选三元组,使得选出的这个三元组是*ao的
分析
如果想直接数的话,第一个想法就是你对每个二元组的第一个元素(以下记为\(a\))和第二个元素(以下记为\(b\))都互不相同然后分开考虑,发现这样你在枚举第一个元素的时候保证的会是第一个元素两两不同,那么这一个三元组一定是合法的,但是第二个元素可能会两两不同,也有可能是有相同的.然后你对\(b\)也这么考虑,发现你最后得到的是保证\(a\)两两不同的+\(b\)两两不同的方案数,由之前的分析可得,这两个可能会有重复计数,而重复的一部分就是\(a\)两两不同并且\(b\)也两两不同的那一部分.然后如果能求出两两都互不相同的方案数,稍微容斥一下就能求出最后的答案.
但是我并不会求,所以考虑另一种做法
发现这个东西我好像确实不会求,所以考虑反着应该怎么求,我们先算出所有三元组的个数,然后再减去所有不合法的方案数,就能算出最后的答案.我们发现,一个三元组不合法,当且仅当对于这个三元组的\(a\)和\(b\)至少有两个元素相等.同时我们发现了一个简化问题的重要结论:只要\(a\)和\(b\)都有两个元素互相相等,那么第三个元素的\(a\)和\(b\)无论怎么样,这个三元组也是不合法的.所以,如果我们枚举一个\((a,b)\),然后三元组中另外两个元素是\((a,y)\)和\((x,b)\)的话,那么这个三元组便是不合法的,我们发现,我们其实就是在所有的元素中选择了一个\(a\)与我们枚举的元素的\(a\)相等的,又选择了一个\(b\)与我们枚举的元素\(b\)相等的,那么这种情况下便会出现一组元素的\(a\)相等,同时也有一组元素的\(b\)相等.所以我们只需要提前处理出每个\(a\)和每个\(b\)的数量,然后相乘一下就是答案.
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
vector<int>bua(n+1,0),bub(n+1,0);
vector<pair<int,int> >v(n+1);
for(int i=1;i<=n;i++){
scanf("%d%d",&v[i].first,&v[i].second);
bua[v[i].first]++,bub[v[i].second]++;
}
long long ans=1ll*n*(n-1)*(n-2)/6;
for(int i=1;i<=n;i++)
ans-=1ll*(bua[v[i].first]-1)*(bub[v[i].second]-1);
printf("%lld\n",ans);
}
return 0;
}
心得
做题的时候看到4种条件中合法的条件有3种其实就应该想到只对剩下的那一种计数更方便,并且转化题意的时候,发现有"一组"这种词的时候就应该想到能不能枚举一个,然后另一个直接算出来。

数学数数题还是不会做...好菜啊
浙公网安备 33010602011771号