POJ-3090-Visible Lattice Points 解题报告

来源:互联网 发布:linux终端输入密码 编辑:程序博客网 时间:2024/06/06 23:24

       欧拉函数题。题意:一个在第一象限的格点(x,y),x和y可以为0且x和y必须是整数。如果一条线段从原点到这个格点不经过其他格点,那么我们称这个格点是有价值的。现在给你范围n,请你求x和y不大于n的情况下有多少有价值的格点。


       我的解题思路:首先,如果从原点到(x,y)这个格点的线段经过其他格点,假设这个格点为(a,b),那么容易知道x / a = y / b,假设等于c,可以断定c必定不等于1,否则格点(a,b)就是格点(x,y),也就是说这个线段不经过其他格点,这和假设相反。因此,可以知道,如果x和y的最大公约数为1,也就是说x与y互素,那么这个格点(x,y)就是有价值的格点。问题就转化成求欧拉函数了,我们可以得到这样的信息:横坐标为x且纵坐标不大于x的有价值格点个数为phi(x),纵坐标也一样。因此我们把phi表存储成前缀和的形式,那么n范围内的有价值格点就是2×phi[n],这和样例答案并不一样,我们需要考虑一下边界情况,当横坐标为1且纵坐标不大于1的有价值格点是(1,1),纵坐标为1时也是这样,因此有价值格点(1,1)算了两次,需要把2×phi[n]减去1。另外,因为x和y可以等于0,所以(1,0)和(0,1)也是有价值的格点,我们需要把这两个点算上,再加上2,最后得到的答案就是2×phi[n]-1,注意这个phi数组要存储为前缀和数组。


       我的解题代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <cctype>#include <cmath>#include <algorithm>using namespace std;const int N = 1003;int phi[N];int n;void InitRead();void DataProcess();void GetPhi(int maxn);int main(){    int t;    scanf("%d", &t);    InitRead();    while (t--)    {        DataProcess();    }    return 0;}void InitRead(){    memset(phi, 0, sizeof(phi));    phi[1] = 1;    GetPhi(N);    for (int i=2; i<N; ++i) phi[i] += phi[i-1]; //存储成前缀和数组    return;}void DataProcess(){    static int tn = 1;    scanf("%d", &n);    printf("%d %d %d\n", tn++, n, phi[n] * 2 + 1);    return;}void GetPhi(int maxn){    for (int i=2; i<maxn; ++i)    {        if (!phi[i])        {            for (int j=i; j<maxn; j+=i)            {                if (!phi[j]) phi[j] = j;                phi[j] -= phi[j] / i;            }        }    }    return;}


0 0
原创粉丝点击