欧拉函数题。题意:一个在第一象限的格点(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;
}