POJ - 3090 Visible Lattice Points (欧拉函数/递推)

题意:给你一个n*n的网格,任意一点和(0,0)连线,可以组成一条直线,前面的点可以挡住后面的点,问你从原点能看到的点到底有多少个

分析:这道题一开始没用欧拉函数做,先用的递推打表的方法,由后一个和前一个的关系得出结果,

其实这是一个很明显的欧拉函数题(菜鸡没发现),我们可以把整个坐标系以 y=x 直线分为两部分,然后求出下半部分的点在乘2就好了,我们可以发现符合条件的点的X,Y坐标必须是互质的,所以就可以利用欧拉函数了,对于横坐标2->n求出对应每个横坐标的互质的纵坐标,然后乘2相加。

递推代码:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))

using namespace std;

typedef pair <int,int> pii;
const int maxn = 1000 + 5 , inf = 0x3f3f3f3f;
int cnt[maxn];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

void cal(){
    mem(cnt);
    cnt[1]=3;
    cnt[2]=5;
    for(int i=3;i<=1000;i++){
        int ans = 0;
        for(int j=1;j<i;j++){
            if(gcd(i,j)==1) ans+=2;
        }
        cnt[i]=cnt[i-1]+ ans;
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
   // Init();
    cal();
    scanf("%d",&T);
    int k = 1;
    while(T--){
        int n;
        scanf("%d",&n);
        printf("%d %d %d\n",k++,n,cnt[n]);
    }
}

欧拉函数代码:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))

using namespace std;

typedef pair <int,int> pii;
const int maxn = 1000 + 5 , inf = 0x3f3f3f3f;
int euler[maxn];

void Init()
{
    memset(euler,0,sizeof(euler));
    euler[1] = 1;
    for(int i = 2;i<maxn;i++){
        if(!euler[i]){
            for(int j = i;j<maxn;j+=i){
                if(!euler[j])euler[j] = j;
                euler[j] = euler[j]/i*(i-1);
            }
        }
    }
}


int main(){
   // freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int k = 1;
    Init();
    scanf("%d",&T);
    while(T--){
        int n,sum = 1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){//这里i代码横坐标,欧拉函数值代表纵坐标
           // cout<<i<<" "<<euler[i]<<endl;
            sum=sum+euler[i]*2;
        }
        cout<<k++<<" "<<n<<" "<<sum<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/Insist_77/article/details/81203838