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;
}

方法二;'线性筛欧拉函数求解(待完善)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值