poj 3090 Visible Lattice Points

先画一条(0, 0)到(n, n)的线,把图分成两部分,两部分是对称的,只需算一部分就好。

取右下半,这一半里的点(x, y)满足x >= y

可以通过欧拉函数计算第k列有多少点能够连到(0, 0)

若x与k的最大公约数d > 1,则(0, 0)与(x, k)点的连线必定会通过(x/d, k/d),就被挡住了

所以能连的线的数目就是比k小的、和k互质的数的个数,然后就是欧拉函数。
方法一:
View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<set>

#include<map>

#include<cstring>

#include<vector>

using namespace std;

bool G[1024][1024];

bool judge( int x , int y )

{

    if( x <= 1000  && y<=1000 ) return true;

    return false;    

}

void Get_map( )

{

    G[0][0] =true;

    for( int i = 0 ; i <= 1000 ; i++ )

    {

       for( int j = (i==0? 1 : 0) ; j <= 1000 ; j++ )

       {

           if( !G[i][j] )

           { 

                int tx = i - 0 ,ty = j - 0;

                int x = i , y = j;

                while( judge( x + tx , y + ty ) )

                {

                     x += tx ; y += ty;

                     G[x][y] = true;     

                }        

           }        

       }

    }

}

int Calculate( int n )

{

    int sum = 0;

    for( int i = 0 ; i <= n ; i++ )

    {

           for( int j  = 0 ; j <= n ; j++ )

              if( !G[i][j] ) sum ++;

    }    

    return sum;

}

int main(  )

{

    memset( G , 0 , sizeof(G ));

    Get_map(  );

    int Case , n;

    while( scanf( "%d",&Case )==1 )

    {

          for( int i = 1 ;i <= Case ; i ++ )

          {

              scanf( "%d",&n );

              printf( "%d %d %d\n",i,n,Calculate( n ) );

          }    

    }

    //system( "pause" );

    return 0;

}
方法二:
View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<set>

#include<map>

#include<cstring>

#include<vector>

using namespace std;

bool G[1024][1024] = {0};

int Gcd( int a , int b )

{

   return b == 0 ? a : Gcd( b ,a%b );

}

void Get_map(  )

{

    int ans = 0;

    for( int i = 0 ; i <= 1000 ; i ++ )

    {

        for( int j = 0 ; j <= i ; j ++ )

        {

            if( Gcd( i , j )==1 )

            {

               G[i][j] = true;    

            }    

        }    

    }

}

int Calculate( int n )

{

    int ans = 0;

    for( int i = 0 ; i <= n ; i ++ )

    {

        for( int j = 0 ; j <= i ; j ++ )

        {

            if( G[i][j] )

            {

              ans++;    

            }    

        }    

    }

    return ans;

}

int main(  )

{

    Get_map( );

    int Case , n;

    while( scanf( "%d",&Case )==1 )

    {

          for( int i = 1 ;i <= Case ; i ++ )

          {

              scanf( "%d",&n );

              printf( "%d %d %d\n",i,n,Calculate( n )*2-1 );

          }    

    }

    //system( "pause" );

    return 0;

}

 

方法三:
容斥定理:
View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<set>

#include<map>

#include<cstring>

#include<vector>

using namespace std;

class Node

{

public:

     int cnt,num[20];

}node[1024];

void Prime( )

{

    int prime[500],cnt=0;

    bool hash[1024] = {0};

    for( int i = 2 ;i <= 40 ; i ++ )

    {

         if( !hash[i] )

         {

             for( int j = 2 ;j*i <=1000; j ++ )

             hash[i*j] = true;        

         }    

    }    

    for( int i = 2 ;i <= 1000; i ++ )

         if( !hash[i] )  prime[cnt++] = i;

    for( int i = 1 ; i <= 1000; i ++ )

    {

        int t = i;

        node[i].cnt = 0;

        for( int j = 0 ; j < cnt ; j++ )

        {

             if(  prime[j] > t ) break;

             if( t % prime[j] == 0 )

             {

                  node[i].num[node[i].cnt++] = prime[j];

                  while( t % prime[j] == 0  )

                         t /= prime[j];

             }

        }    

    }

}

int DFS( int t , int n  , int k )

{

    int ans = 0;

    for( int i = t ; i < node[k].cnt ; i ++ )

         ans += n/node[k].num[i] - DFS( i + 1 , n/node[k].num[i] , k );

    return ans;     

}

int main(  )

{

    int Case,n;

    Prime();

    while( scanf( "%d",&Case )==1 )

    {

         for( int j = 1 ; j <= Case ; j ++ )

         {

              int ans = 0;

              scanf( "%d",&n );

              for( int i = 1 ; i <= n ; i ++  )

                   ans += n - DFS( 0, n , i );

             printf( "%d %d %d\n",j , n ,ans + 2 );

         }    

    }

    //system( "pause" );

    return 0;

}

 



你可能感兴趣的:(visible)