@xzyxzy
2018-01-22T16:48:33.000000Z
字数 2316
阅读 1382
题解
的网格中每个小格为,标号为到每个小格(除)中有一个以其中心为圆心,半径为的圆,给你求从方格的中心点能够看到的圆的个数。(一个圆能被看到,当且仅当圆周上存在一个点能被看到;某个点能被看到,当且仅当点与这个点的连线之间,和其他圆没有交点)
一个圆能被看到,当且仅当与该圆的圆心的连线与其他圆没有交点
可以产生干扰的圆一定关于连线的中点中心对称,所以对于该圆的圆周上一点,和与关于连线轴对称的,当不断增大时,必然同时不被看见,最后剩下的那个点就是连线与圆周的交点,即得证。
与连线,既然干扰的圆都中心对称,那么只需要考虑在连线下方最接近连线的个圆
令干扰圆为,那么
由点到直线距离公式(点,直线)
将上式进行反演后可以得到
感谢:YMDragon,SYC
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<map>
#define ll long long
using 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;
}