BZOJ系列1041《[HAOI2008]圆上的整点》题解

Description

求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。

Input

r

Output

整点个数

Sample Input

4

Sample Output

4

HINT

n<=2000 000 000


不得不吐槽一下,作为一名河南人,0708年那会我们河南水平很低,花钱让雅礼的朱全民老师出我们的省选题,

质量很高,但都不会做,这道题当时河南没一个人做出来,那时往往是可以60分就进队的,呵呵。

如今,我们河南的实力不说和浙江和牛棚湖南比,但是还是有很大提升的,这几年的省选题却开始糊弄了,

找郑州大学的人出不要钱的题,真是醉了,14年省选题考纯暴力,没动规没图论,数据还有错,

真是白瞎了这几年实力的增长,有实力了考简单题,没实力了要考各种难。

好吧!吐槽归吐槽,还是要好好面对的,希望明年省选靠点谱吧!

说题,很难,真的没有任何头绪,枚举肯定是不行的,所以就应该找找数学方法了。

以下转自某神犇blog:
//==========================分割线==========================
这里先只考虑x,y都大于0的情况


如果x^2+y^2=r^2,则(r-x)(r+x)=y*y


令d=gcd(r-x,r+x),r-x=d*u^2,r+x=d*v^2,显然有gcd(u,v)=1且u<v


有2r=d*(u^2+v^2),y=d*u*v,x=d(v^2-u^2)/2


枚举2r的约数d,再花费sqrt(2r/d)的时间枚举u,求出v=sqrt(2r/d-u^2)然后判断gcd(u,v)=1。

一个数字的平均约数个数为logn个,然后后面那个sqrt(2*r/d)在很多情况下都很小,所以比较快。


最后结果乘以4(四个象限)+4(坐标轴上)即可
//==========================分割线==========================

方法不得不称之曰奇妙,时间复杂度是一定不会超的,完美解决!

代码如下:

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll R,ans=0;
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
void lyd(ll d)
{
	ll v;
	for(ll u=1;u<=(ll)sqrt(1.0*2*R/d);u++)
	{
		v=(ll)sqrt(1.0*2*R/d-u*u*1.0);
		if(gcd(v,u)==1&&u<=v&&d*(u*u+v*v)==2*R) ans++;
	}
}
int main()
{
	scanf("%lld",&R);
	for(ll i=1;i<=(ll)sqrt(1.0*R*2);i++)
		if(2*R%i==0)
		{
			if((ll)i*i!=2*R)
			{
				lyd(2*R/i);
				lyd(i);
			}
			else lyd(i);
		}
	printf("%lld\n",ans*4);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值