样例输入:
10 114514
样例输出:
35
题意:给定一个n个点的完全图,每条边的权值可能为0,也可能为1,让我们找出由三条权值相同的边组成的三角形的个数,每条边的边权是通过随机数给的。
这道题是通过反向思考来解决的,有n个点,由于是一个完全图,所以任意三个点都能够组成一个三角形,那么所有三角形的总个数就是C(n,3)=n*(n-1)*(n-2)/6
现在我们只要找出来边权不完全相同的三角形的个数即可,我们拿一个权值分别为0,0,1的三角形来举例:
我们先来枚举以A的两条边组成的三角形中权值不完全相同的三角形的个数,那么我们可以任意选一条以A作为起始点的权值为0的边以及选一条以A作为起始点的权值为1的边,那么如果这两条边都参与组成三角形的话一定不能组成一个三个权值完全相同的三角形,那么我们只需要记录从A出发权值为0的边数cnt,由于是一个完全图,那么从A出发的边一共有n-1条,那么从A出发权值为1的边一共有n-1-cnt个,所以这样的三角形一共有cnt*(n-cnt-1)个三角形,但是对于这个三角形而言,当我们遍历C点时也会记录一次,但是遍历B时就不会被记录,因为这个三角形中由B出发的两条边权都是0,所以对于每个不满足题意的三角形我们都会重复记录一次,所以不满足题意的三角形的总个数我们最后需要除以2,再用图中总的三角形个数-不满足题意的三角形的个数即可得到答案。
下面是代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int N=8e3+10;
namespace GenHelper
{
unsigned z1,z2,z3,z4,b,u;
unsigned get()
{
b=((z1<<6)^z1)>>13;
z1=((z1&4294967294U)<<18)^b;
b=((z2<<2)^z2)>>27;
z2=((z2&4294967288U)<<2)^b;
b=((z3<<13)^z3)>>21;
z3=((z3&4294967280U)<<7)^b;
b=((z4<<3)^z4)>>12;
z4=((z4&4294967168U)<<13)^b;
return (z1^z2^z3^z4);
}
bool read() {
while (!u) u = get();
bool res = u & 1;
u >>= 1; return res;
}
void srand(int x)
{
z1=x;
z2=(~x)^0x233333333U;
z3=x^0x1234598766U;
z4=(~x)+51;
u = 0;
}
}
using namespace GenHelper;
bool edge[8005][8005];
vector<int>p[N];
int main() {
int n, seed;
cin >> n >> seed;
srand(seed);
long long sum=0;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edge[j][i] = edge[i][j] = read();
for(int i=0;i<n;i++)
{
long long cnt=0;
for(int j=0;j<n;j++)
if(edge[i][j]) cnt++;
sum+=cnt*(n-1-cnt);
}
long long ans=(long long)n*(n-1)/2*(n-2)/3;
cout<<ans-sum/2;
return 0;
}
//10 114514