POJ_3090_Visible Lattice Points

Visible Lattice Points
Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 7303
Accepted: 4428

Description

A lattice point (xy) 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 (xy) 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 (xy) with 0 ≤ xy ≤ 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 (xy) with 0 ≤ xy ≤ 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

Source

  • 2017计蒜客初赛的一道题可能是从这里来的吧
  • 那个初赛里面有一个快速枚举同一条线段上的整数点的操作
  • 当时惊为天人,其实还是自己太鶸~
  • 那么对于这道题来说,不难发现一条射线的第一个点的坐标(x,y)==1
  • 由于该题要求的所有射线都是自原点发出,所以后续的在射线上被第一个点遮挡的点坐标的gcd不为1,对应坐标是第一个点的k倍
  • 不难想到用gcd:
  • int gcd(int x, int y){
    	return y?gcd(y,x%y):x;
    }
    int cal(int n){
    	int ans=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<i;j++)
    			if(1==gcd(i,j))
    				ans++;
    	return 2*ans + 3;
    }
  • 方法没错,但是超时
  • 接着看,这里gcd的操作等价于求1到n的欧拉函数:
  • int cal(int n){
    	int ans=0;
    	for(int i=1;i<=n;i++)
    		ans+=phi[i];
    	return ans*2 + 1;
    }
  • 然后就A了呀

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long           LL ;
typedef unsigned long long ULL ;
const int    maxn = 1000 + 10  ;
const int    inf  = 0x3f3f3f3f ;
const int    npos = -1         ;
const int    mod  = 1e9 + 7    ;
const int    mxx  = 100 + 5    ;
const double eps  = 1e-6       ;

int phi[maxn], minDiv[maxn], sum[maxn];
void genPhi(void){
	for(int i=1;i<maxn;i++)
		minDiv[i]=i;
	for(int i=2;i*i<maxn;i++)
		if(minDiv[i]==i)
			for(int j=i*i;j<maxn;j+=i)
				minDiv[j]=i;
	phi[1]=1;
	for(int i=2;i<maxn;i++){
		phi[i]=phi[i/minDiv[i]];
		if((i/minDiv[i]) % minDiv[i] == 0)
			phi[i]*=minDiv[i];
		else
			phi[i]*=minDiv[i]-1;

	}
}
int cal(int n){
	int ans=0;
	for(int i=1;i<=n;i++)
		ans+=phi[i];
	return ans*2 + 1;
}
// int gcd(int x, int y){
// 	return y?gcd(y,x%y):x;
// }
// int cal(int n){
// 	int ans=0;
// 	for(int i=1;i<=n;i++)
// 		for(int j=1;j<i;j++)
// 			if(1==gcd(i,j))
// 				ans++;
// 	return 2*ans + 3;
// }
int T, kase, n;
int main(){
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	genPhi();
	while(~scanf("%d",&T)){
		for(kase=1;kase<=T;kase++){
			scanf("%d",&n);
			printf("%d %d %d\n",kase,n,cal(n));
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值