@xzyxzy
2018-01-22T08:48:33.000000Z
字数 2316
阅读 1568
题解
的网格中每个小格为,标号为到每个小格(除)中有一个以其中心为圆心,半径为的圆,给你求从方格的中心点能够看到的圆的个数。(一个圆能被看到,当且仅当圆周上存在一个点能被看到;某个点能被看到,当且仅当点与这个点的连线之间,和其他圆没有交点)
一个圆能被看到,当且仅当与该圆的圆心的连线与其他圆没有交点
可以产生干扰的圆一定关于连线的中点中心对称,所以对于该圆的圆周上一点,和与关于连线轴对称的,当不断增大时,必然同时不被看见,最后剩下的那个点就是连线与圆周的交点,即得证。
与连线,既然干扰的圆都中心对称,那么只需要考虑在连线下方最接近连线的个圆
令干扰圆为,那么
由点到直线距离公式(点,直线)
将上式进行反演后可以得到
感谢:YMDragon,SYC
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<map>#define ll long longusing namespace std;int read(){char ch=getchar();int h=0;while(ch>'9'||ch<'0')ch=getchar();while(ch>='0'&&ch<='9'){h=h*10+ch-'0';ch=getchar();}return h;}const int MAXN=1e6;int mu[MAXN+1],pri[MAXN>>2],tot;bool ispri[MAXN+1];void Mobius(){mu[1]=1;ispri[1]=1;for(int i=2;i<=MAXN;i++){if(!ispri[i]){pri[++tot]=i;mu[i]=-1;}for(int j=1;j<=tot&&i*pri[j]<=MAXN;j++){ispri[i*pri[j]]=1;if(i%pri[j])mu[i*pri[j]]=-mu[i];else break;}}}map<pair<ll,int>,ll>M;ll Calc(ll m,int n){if(M.find(make_pair(m,n))!=M.end())return M[make_pair(m,n)];ll ans=0;for(int i=1;1LL*i*i<=m&&i<=n;i++)ans+=min(n,int(sqrt(m-1LL*i*i)));M[make_pair(m,n)]=ans;return ans;}int main(){Mobius();int N=read()-1,R=read();ll m=((ll)1e12-1)/R/R,ans=0;for(int i=1;1LL*i*i<=m;i++)ans+=mu[i]*Calc(m/i/i,N/i);printf("%lld\n",ans+2);return 0;}