题意:
给定一个整数N,你要写一个程序来计算出两个关于以下方程解的量:
x^2 + y^2 = z^2
其中x,y和Z都限定为正整数且小于等于N。你要计算出所有满足x < y < z的三元组(x,y,z)的数量,并且使得x,y和z两两互质,即没有大于1的公因数。你还要计算出所有满足下面条件的p的数量:0 < p ≤ N,且p没有在所有这样的三元组中出现(并不限定为两两互质的三元组)。
解析:
由以上定义我们推导出勾股公式:
对于a2+b2=c2,求出所有满足条件的(a,b,c)三元组,输出a,b,c三个互质的组别的数量和从1到N中所有
的三元组中都没有出现过的数字的个数。
要求互质毕达哥拉斯三元组,可直接得到:
a = m^2-n^2 b = 2mn c = m^2+n^2
因为三个变量之间两两互质,所以a,b中必为一奇一偶。
(详细证明见:http://www.cnblogs.com/devymex/archive/2010/08/07/1799713.html)
因此问题的复杂度就可以降为O(m*n),即:最坏1000*1000。
除互质勾股数外,其他所有勾股数三元组都可以由求出的互质勾股数乘以一定的系数得到,由此可以得到三元组没出现的数字的个数(n - 所有勾股数个数)。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1000001;
bool used[N];
int n;
void init() {
for(int i = 0; i <= n; i++) {
used[i] = false;
}
}
int gcd(int x, int y) {
if(y == 0) return x;
return gcd(y, x % y);
}
void solve() {
int limit = (int)floor(sqrt(n));
int cnt = 0, cnt2 = 0;
ll a, b, c;
for(int s = 1; s <= limit; s++) {
for(int r = s+1; r <= limit; r += 2) {
c = r*r + s*s;
if(gcd(r,s) == 1 && c <= n) {
a = r*r - s*s;
b = 2*r*s;
cnt++;
for(int i = 1; i * c <= n; i++) {
used[a*i] = used[b*i] = used[c*i] = true;
}
}
}
}
for(int i = 1; i <= n; i++) {
if(!used[i]) cnt2++;
}
printf("%d %d\n",cnt,cnt2);
}
int main() {
while(scanf("%d", &n) != EOF) {
init();
solve();
}
return 0;
}