题意
就是站在原点(0, 0),在 0 ≤ x , y ≤ n 0 \le x, y \le n 0≤x,y≤n,你能直接看到的点有多少个点(x, y)。
思路
我们先把整张图按照对角线分成两个部分。对角线这条线上的我们先不考虑其实(就只有一个点会被看到)。我们只看其中的一部分:
n | cnt |
---|---|
1 | 1 |
2 | 1+1 |
3 | 1+1+2 |
4 | 1+1+2+2 |
5 | 1+1+2+2+4 |
每一行最后一个数代表这一行有多少个点可以被看到。
通过发现我们可以知道每一行能被看到的书就是
ϕ
(
i
)
\phi(i)
ϕ(i)。
另一部分的个数其实是相同的。那么最后答案我们在加上对角线这个只有一个的点。
a n s = s u m ( n ) ∗ 2 + 1 ans = sum(n) * 2 + 1 ans=sum(n)∗2+1,sum代表的是前n个数的 ϕ ( i ) \phi(i) ϕ(i)的和也可以理解为前缀和。所以我们只有运用筛法把一千以内的所有数的欧拉函数给求出来,最后再求一遍前缀和就可以利用上述式子求出答案了。
代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
#define xx first
#define yy second
using namespace std;
const int N = 2e3 + 10;
int n, _;
int pr[N], cnt, phi[N], sum[N];
bool st[N];
void euller()
{
phi[1] = 1;
for(int i = 2; i < N; i ++)
{
if(!st[i])
{
pr[cnt++] = i;
phi[i] = i-1;
}
for(int j = 0; pr[j]*i < N; j ++)
{
st[pr[j]*i] = 1;
if(i % pr[j] == 0)
{
phi[i * pr[j]] = phi[i] * pr[j];
break;
}
phi[i * pr[j]] = phi[i] * (pr[j] - 1);
}
}
for(int i = 1; i < N; i ++)
{
sum[i] = sum[i-1] + phi[i];
}
}
void solve(int id)
{
cin >> n;
cout << id << " " << n << " ";
cout << sum[n] * 2 + 1 << endl;
}
signed main()
{
IOS;
euller();
cin >> _;
for(int i = 1; i <= _; i ++) solve(i);
return 0;
}