這一題是給一個數字N:
1. 找出所有小於等於N的正整數中,互質的畢式組數(如: (3, 4, 5)是一組互質的畢式組數)數量。
2. 找出所有小於等於N的正整數中,不能構成畢式組數(不需是互質的畢式組數)的數字數量。
乍看之下只要用brute force找出所有的畢式數對即可,但由於N最大值是1,000,000,光要建立小於1,000,000的質數表就已經超過3秒鐘的Time Limit,所以一定要找其他方法。
參考Algorithmist,才發現使用畢式定理的通解,處理時間會大大的縮短。
X^2 + Y^2 = Z^2
( r^2 - s^2 )^2 + ( 2rs )^2 = ( r^2 + s^2 )^2
由於Z=(r^2+s^2),要找出 Z<N 即是 (r^2+s^2)<N,因此r, s < N^(1/2),搜尋數量縮減到根號N,也就是最大1000!
而互質且一奇一偶的(r, s),可以產生所有互質的畢式組數。在乘上倍數後便可以找出其他非互質的畢式組數了。
TIPS
記錄數字是否為畢式組數的陣列要用char型別,int型別無法開到1,000,000
CODE
#include <stdio.h>
int p, prime[200];
void findprime(void);
int rp(int a, int b);
int main(){
int i, j;
int n, r, s, rsq, ssq, rpt;
char num[1000002]="";
/*Find all prime numbers between 1 and 1000*/
findprime();
while( scanf("%d", &n) != EOF ){
rpt = 0;
for(r=2; (rsq = r*r)<n; r++){
for(s=1; s<r && (rsq+(ssq = s*s)<=n); s++){
if( ((r%2 == 1) ^ (s%2 == 1)) && (rp(r,s) == 1) ){
rpt++;
/*time the triple pair*/
for(i=1; (i*(rsq+ssq))<=n; i++)
num[ i*(rsq - ssq) ] = num[ i*(2*r*s) ] = num[ i*(rsq + ssq) ] = 1;
}/*(r, s) pair can generate relatively prime triple*/
}/*s*/
}/*r*/
printf("%d ", rpt);
j = 0;
for(i=1; i<=n; i++){
if( num[i] == 1 )
num[i] = 0;
else
j++;
}
printf("%d\n", j);
}/*while input data*/
exit(0);
}
void findprime(void){
int i, j, tmp[1001];
for(i=2; i<1001; i++)
tmp[i] = 1;
p = 0;
for(i=2; i<1001; i++){
if( tmp[i] == 1 ){
prime[p] = i;
p++;
for(j=(i+i); j<1001; j+=i)
tmp[j] = 0;
}
}
}
int rp(int a, int b){
int i;
for(i=0; i<p && prime[i]<a ; i++)
if( (a % prime[i] == 0) && (b % prime[i] == 0) )
return 0;
return 1;
}
No comments:
Post a Comment