1. 程式人生 > 實用技巧 >CSUST 4007-你真的會圖論嗎?(思維-三元環)

CSUST 4007-你真的會圖論嗎?(思維-三元環)

題目連結:http://acm.csust.edu.cn/problem/4007
部落格園食用連結:https://blog.csdn.net/qq_43906000/article/details/107813983

Description

給你一張完全無向圖,每條邊有兩種顏色(黑色或者白色),你需要求出有多少個三元環,路徑上邊的顏色相同給你一張完全無向圖,每條邊有兩種顏色(黑色或者白色),你需要求出有多少個三元環,路徑上邊的顏色相同

Input
第一行一個正整數\(n\),表示這張完全圖的點數.\((1 \leq n \leq 5e3)\)

第二行五個整數,\(A,B,C,P,D,1 \leq A,B,C,P,D \leq 10^9\)


,且\(D \leq P\),然後我們規定,對於邊\(i,j(i \lt j)\),如果\((A(i+j)^2 + B(i-j)^2 +C) \mod P>D\),則該邊為黑色,否則為白色.

Output
輸出一個數表示結果

Sample Input 1
6
2 3 4 11 5
Sample Output 1
6

正所謂正難則反,對於直接選出同色的三元環可能會不知道怎麼入手,那麼我們考慮將所有的三元環減去不符合條件的三元環。那麼總共的三元環個數很好算,就是\(C_n^3\),對於不符合條件的三元環,我們知道他們一定會有兩條邊顏色相異,而這兩條邊一定是由某個點延伸出去的,那麼我們直接列舉這個點,然後再列舉他的邊就好了(也就是列舉其他所有的點)

接下來的關鍵就是如何在一個點的所有邊中計算不合法的三元環了。為了不重複,我們對該點延伸的每個邊找在他前面的和他顏色互異的邊,然後直接加上就好了。但所需要考慮的是重複的問題,雖然對於點內的三元環來講沒有重複了,但對於點之間的三元環就可能會出現重複了,比如說對於如下三元環而言:

2到5到6是相異的,但一定會有一個點,假設是5使得5-6,5-2同色,也一定會有一個點假設是6使得6-5,6-2異色。那麼也就是一個不合法的三元環一定會重複2次計算。

那麼程式碼也就出來了。
以下是AC程式碼:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mac=5e3+10;

bool color[mac][mac];//0為白色,1為黑色

ll pw(int x) {return 1LL*x*x;}

int main(int argc, char const *argv[])
{
	int n;
	scanf ("%d",&n);
	int a,b,c,d,p;
	scanf ("%d%d%d%d%d",&a,&b,&c,&p,&d);
	for (int i=1; i<=n; i++){
		for (int j=i+1; j<=n; j++){
			ll val=(1LL*a*pw(i+j)+1LL*b*pw(i-j)+c)%p;
			if (val>d) {color[i][j]=color[j][i]=true;}
			else {color[i][j]=color[j][i]=false; }
		}
	}
	ll ans=1LL*n*(n-1)*(n-2)/6;
	ll res=0;
	for (int i=1; i<=n; i++){
		int black=0,white=0;
		for (int j=1; j<=n; j++){
			if (i==j) continue;
			if (color[i][j]) {res+=white; black++;}
			else {res+=black; white++;}
		}
	}
	ans-=res/2;
	printf("%lld\n",ans);
	return 0;
}