/**//* 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
搜索
最新评论
|
|