UVA 10214 Trees in a Wood(欧拉函数)

题意:给你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);
    }

}

 

posted @ 2017-04-12 20:45  专注如一  阅读(303)  评论(0编辑  收藏  举报