ACWing201. 可見的點(POJ3090)

題目傳送門:https://www.acwing.com/problem/content/description/203/
題目大意:
在一個平面直角座標系的第一象限內,如果一個點(x,y)與原點(0,0)的連線中沒有通過其他任何點,則稱該點在原點處是可見的。
例如,點(4,2)就是不可見的,因爲它與原點的連線會通過點(2,1)。
部分可見點與原點的連線如下圖所示:
在這裏插入圖片描述
編寫一個程序,計算給定整數N的情況下,滿足0≤x,y≤N的可見點(x,y)的數量(可見點不包括原點)。
輸入格式
第一行包含整數C,表示共有C組測試數據。
每組測試數據佔一行,包含一個整數N。
輸出格式
每組測試數據的輸出佔據一行。
應包括:測試數據的編號(從1開始),該組測試數據對應的N以及可見點的數量。
同行數據之間用空格隔開。
數據範圍
1≤N,C≤1000
輸入樣例:
4
2
4
5
231
輸出樣例:
1 2 5
2 4 13
3 5 21
4 231 32549
【分析】
  根據題目我們發現除了(1,0),(0,1),(1,1)這三個釘子外,一個釘子(x,y)要被看到,需要x!= y且 x,y均在[1,n]內,而且gcd(x,y) == 1。
  我們還能發現這些能被看到的釘子數是以(0,0)到(n,n)這條直線對稱的,那麼我們只需要考慮一半,對於每個2<=y< = n,我們需要統計1<=x < y,這樣與y互質的x的數量恰好是phi(y).因此本題對於n的答案就是3 + 2 * sum(phi[i])(2<=i<= n),其中求和部分可以用前綴和預處理好。
  本着想用最原始的方法一個個求歐拉函數的方法,寫了此代碼,竟然過了。
  時間複雜度分析:O(N sqrt(N))

#include<bits/stdc++.h>
using namespace std;
 int t,n;
 int phi[1006],s[1006];
 int eular(int x){
 	int ans = x;
 	for(int i = 2,tem = sqrt(x); i <= tem;i++){
 		if(x %i ==0){
 			ans  = ans * (i -1) / i;
 			while(x % i == 0 ){
 				x = x / i;
 			}
 		}
 	}
 	if(x > 1) ans = ans * (x-1) / x;
 	return ans;
 }
int main(){
 	cin >> t;
 	for(int i = 2;i<= 1000;i++)
	 	phi[i] = eular(i); 
	for(int i = 2; i<= 1000; i++){
		s[i] = s[i-1] + 2 * phi[i];
	}
	for(int i = 1;i<=t ;i++){
		cin >> n;
		if (n == 0)cout << i << " " << n <<" " << 0 << endl;
		else cout << i << " " << n <<" " << 3 + s[n] << endl;
	}   
	return 0;
}

方法二;'線性篩歐拉函數求解(待完善)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章