 /**//*
n<=10^6個點,每個點有權值a[i]<=10^7 各不相同
若存在一個數x,使得a[i],a[j],x is a beautiful triple
即a^2 + b^2 = c^2 a,b,c互素
則i可以傳播laugh到j
問最少需要需要讓多少個頂點自行laugh,然后傳播到全部的頂點

看了解題報告的
并查集做
但如何判斷beautiful triple 兩兩判斷O(n^2)會超時

有個性質:對于滿足a^2 + b^2 = c^2的數,可用勾股數公式生成:
(x^2-y^2 , 2xy , x^2+y^2) x>y
該公式能生成所有的素勾股數(互質),需1奇1偶 ,且gcd(x,y) = 1
也能生出部分派生勾股數(如 6 8 10) , 2奇或2偶
由于a[i]<=MAX MAX= 10^7
所以必有x^2-y^2 <= MAX , 2xy <= MAX 但x^2+y^2不一定<= MAX
2y^2<=MAX
x^2<=MAX+y^2<=3MAX/2
=> x<=sqrt(3MAX/2) , y <= sqrt(MAX/2)
所以枚舉x,y復雜度為O(MAX)
(注意x,y是1奇1偶且gcd(x,y) = 1)

參考watashi代碼寫的
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>

using namespace std;

const int MAX = 10000000;
const int MAXX = (int)(sqrt(1.5*MAX) + 0.5);
const int MAXN = 1000000;

 struct DisjointSet {
int fa[MAXN];
 void init(int n) {
 for(int i = 1 ; i <= n ; i++) {
fa[i] = i;
}
}
 int root(int x) {
return x == fa[x] ? x : fa[x] = root(fa[x]);
}
 bool join(int a ,int b) {
a = root(a);
b = root(b);
 if(a != b) {
fa[a] = b;
return true;
}
return false;
}
};

DisjointSet ds;
int id[MAX+10];

 inline int gcd(int x , int y) {
return y == 0 ? x : gcd(y , x % y);
}

 bool gao(int a , int b) {
return id[a] > 0 && id[b] > 0 && ds.join(id[a],id[b]);
}

int main()
  {
 for(int n ; ~scanf("%d",&n) ; ) {
fill(id,id+MAX+1,0);
ds.init(n);
 for(int i = 1,x; i <= n ; i++) {
scanf("%d",&x);
id[x] = i;
}
 for(int x = 1 ; x <= MAXX ; x++) {
 for(int y = x % 2 + 1 ; y < x ; y += 2) {
 if(gcd(x, y) == 1) {//need it 
int a = x*x - y*y;
int b = 2*x*y;
int c = x*x + y*y;
 if(a > MAX || b > MAX) {
continue;
}
n -= gao(a,b);
 if(c <= MAX) {
n -= gao(a,c);
n -= gao(b,c);
}
}
}
}
printf("%d\n",n);
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|