題目描述
A lattice point (x, y) in the first quadrant (x and y are integers greater than or equal to 0), other than the origin, is visible from the origin if the line from (0, 0) to (x, y) does not pass through any other lattice point. For example, the point (4, 2) is not visible since the line from the origin passes through (2, 1). The figure below shows the points (x, y) with 0 ≤ x, y ≤ 5 with lines from the origin to the visible points.

Write a program which, given a value for the size, N, computes the number of visible points (x, y) with 0 ≤ x, y ≤ N.
Input
The first line of input contains a single integer C (1 ≤ C ≤ 1000) which is the number of datasets that follow.
Each dataset consists of a single line of input containing a single integer N (1 ≤ N ≤ 1000), which is the size.
Output
For each dataset, there is to be one line of output consisting of: the dataset number starting at 1, a single space, the size, a single space and the number of visible points for that size.
Sample Input
4
2
4
5
231
Sample Output
1 2 5
2 4 13
3 5 21
4 231 32549
大致題意
求位于(0,0)時,向四周看能看到多少個點,一個點能被看到,當且僅當連接它和(0,0)的線段上沒有其他點,
分析
除了(1,0),(0,1),(1,1)三個點外,一個點能被看到當且僅當x≠y且gcd(x,y)=1,即求x與y互質的點的數量,此時想到歐拉函式,
因為能被看到的點關于(0,0)(N,N)直線對稱,所以只要求上半部分每個y(2~N)的歐拉函式之和ans,可得總數為2*ans+3,
代碼
#include<cstdio>//使用scanf和printf的頭檔案
#include<cstring>//使用C風格字串函式的頭檔案
#include<algorithm>//使用演算法庫的頭檔案,max,min,swap,sort等
#include<iostream>//使用cin,cout的頭檔案
#include<string>//使用string時的頭檔案
#include<vector>//使用vector時的頭檔案
#include<cmath>//數學函式的頭檔案
#include<set>//使用set的頭檔案
using namespace std;
#define ll unsigned long long
ll n,c,size,ans;
ll v[1010],prime[1010],phi[1010],m;//phi[i] i的歐拉函式值
void eular(){
//初始化陣列
memset(v,0,sizeof(v));
memset(phi,0,sizeof(phi));
memset(prime,0,sizeof(prime));
m=0;//記錄素數數量
//線性篩法 求出2~1000中每個數的歐拉函式
for(ll a=2;a<=1000;a++){
if(!v[a]){ //篩素數,同時得此素數的歐拉函式
v[a]=a;
prime[++m]=a;
phi[a]=a-1;
}
for(ll b=1;b<=m;b++){ //遍歷 小于等于 a 的素數
if(prime[b]>v[a]||prime[b]*a>1000) break; //如果此素數prime[b]大于 a 的最小質因子 或者 prime[b]*a > 上限1000,則停止遍歷
v[a*prime[b]]=prime[b]; //每個倍數用最小質因子prime[b]標記
phi[a*prime[b]]=phi[a]*(a%prime[b]? prime[b]-1:prime[b]); //根據歐拉函式性質4、5
}
}
}
int main(){
cin>>c;
//預處理 2~1000的歐拉函式phi[i]
eular();
for(ll i=1;i<=c;i++){
ans=0;
cin>>n;
for(ll j=2;j<=n;j++){
ans+=phi[j];
}
printf("%llu %llu %llu\n",i,n,2*ans+3);//看題目可推出公式 2*(2~n歐拉函式之和)+3
}
return 0;
}
線性篩法
每個合數必有一個最小素因子,用這個最小素因子把合數篩掉,避免同個合數被多個因子重復篩,
你可以找到更多關于的資訊 線性篩法程序 here.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/238545.html
標籤:其他
