题目:https://ac.nowcoder.com/acm/contest/11254/J
题意:给你一张图,n个点,任何两个点之间都有边,边权要么是0要么是1,问三条边权相等的三角形的数量。
题解:图的大小给的是8000,暴力三重循环肯定不行。假设这个三角形中有一个点是重要点,那么咱枚举每一个点当三角形中的重要点;首先,任何三个点都能构成三角形(因为任何两个点之间都有边),所有的三角形只有两种情况,三条边都相等,三条边中有一条边和其他两条边不同,可以看出,这两种三角形有一个共同点,都有两条边是相等的(这两条边挨着-连着同一个点–显而易见);咱们可以先求出连接i这个点为1的边的数量a,为0的边的数量b,那么a*(a-1)/2,和b*(b-1)/2,就是枚举i这个点为重要点,且这个点连接的两条边都相等num1=b*(b-1)/2+a*(a-1)/2,就是所有三角形有一个点为连着的两条边相同的数量(这里先把重的三角形算入),根据上面的描述,这个答案包含着所有三角形;令num2=a*b,代表有一个点左右两边的边不相等的数量,因为一个第二种三角型中有两个这样点的,所有要除以2,所有num1-num2/2,就是三条边都相等的三角形的数量,但是因为这个三角形三个点都一模一样,所以算出来的答案除以三就是正确答案。
主要:要开longlong ,题目中会超int。
#include <bits/stdc++.h>
using namespace std;
#define int long long
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;
}
} // namespace GenHelper
using namespace GenHelper;
bool edge[8005][8005];
int num[8005];
signed main() {
int n, seed;
cin >> n >> seed;
srand(seed);
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) edge[j][i] = edge[i][j] = read();
int res = 0, a = 0, b = 0;
for (int i = 0; i < n; i++) {
int n1 = 0, n0 = 0;
for (int j = 0; j < n; j++) {
if (i == j) continue;
if (edge[i][j])
n1++;
else if (!edge[i][j])
n0++;
}
a += n0 * (n0 - 1) / 2 + n1 * (n1 - 1) / 2;
b += n0 * n1;
}
res = (a - b / 2) / 3;
cout << res << endl;
return 0;
}