题意:给你a、b(a<=2000,b<=2000000),问你从原点可以看到范围在(-a<=x<=a,-b<=y<=b)内整数点的个数
题解:首先只需要计算第一象限的点得到答案为ans,再计算ans*4+4就好了;原因是四象限一样,接着上下左右各加上一个点
在第一象限上就是求x属于[1,a]y属于[1,b]时gcd(x,y)==1的总个数
可以想到欧拉函数phi[i]=n,因为他的定义就是小于等于i的正整数中有n个与i互质
而且根据gcd(a,b)=gcd(a+b,a)=gcd(2*a+b,a),因此可以使用i枚举a
通过求出欧拉函数在[1,i][i+1,2*i]...各有phi[i]个进行计算,接着多了不能成为一个完整区间的一些值就直接暴力
import java.text.DecimalFormat; import java.util.Scanner; public class Main{ static int Max=2010; static int[] phi=new int[Max]; static{ phi[1]=1; for(int i=2;i<Max;++i){ if(phi[i]==0){ for(int j=i;j<Max;j+=i){ if(phi[j]==0) phi[j]=j; phi[j]=phi[j]/i*(i-1); } } } } public static void main(String[] args) { long n,m; Scanner sc=new Scanner(System.in); while(sc.hasNext()){ n=sc.nextLong(); m=sc.nextLong(); if(n+m==0L) break; DecimalFormat df=new DecimalFormat("0.0000000");//小数点后7位 System.out.println(df.format(Solve(n,m))); } } private static Double Solve(long n, long m) { long res=0L; for(int i=1;i<=n;++i){ long multipe=m/i; res+=multipe*phi[i];//倍数直接增加 for(int j=(int) (multipe*i+1);j<=m;++j){ if(Gcd(i,j)==1) res++; } } return ((double)res*4+4)/((n*2.0+1)*(m*2.0+1)-1.0); } private static int Gcd(int i, int j) { if(j==0) return i; else return Gcd(j, i%j); } }