爱思创 181314 仪仗队 题解
题目大意
求出在 n*n 的方阵中,在(0,0)位置上能看到的人数

小A: 可以画一条对角线,使答案变成 \(2·sum+1\)

题目思路
小B: 这道题和兔八哥与猎人类似,那一题我们判断了x差与y差是否互质,这一题应该也可以这么做
小A: 那么主要思路有了,就只差优化统计x与y互质的位置了
这里补充一下埃拉托斯特尼筛法
对于任意一个大于 1 的正整数 n,那么它的 x 倍就是合数(x > 1)。利用这个结论,我们可以避免很多次不必要的检测。
如果我们从小到大考虑每个数,然后同时把当前这个数的所有(比自己大的)倍数记为合数,那么运行结束的时候没有被标记的数就是素数了。
bool vis[N];//是否为质数
int p[M];//质数表
int esieve(int n)
{
int cnt = 0;//质数个数
vis[0] = vis[1] = true;//0和1虽然不是合数,但也不是质数
for(int i = 2; i * i <= n; i ++)
{
if(!vis[i])//质数的倍数除本身以外都是合数
{
for(int j = i * i; j <= n; j += i)
{
vis[j] = true;//j不是质数
}
}
}
for(int i = 2; i <= n; i ++)
{
if(!vis[i]) p[++cnt] = i;//统计质数
}
return cnt;
}
再讲一下欧拉函数,及 \(\phi(n)\),表示的是小于等于 n 和 n 互质的数的个数。
小B: 比如 \(\phi(1) = 1\),并且如果i是质数,则 \(phi(i)=i-1\)
小A: 再把两者结合一下,我们就能批量求解欧拉函数了
void esieve(int n)
{
for(int i = 1; i <= n; i ++)
{
phi[i] = i;
}
for(int i = 2; i <= n; i ++)
{
if(!vis[i])
{
for(int j = i; j <= n; j += i)
{
vis[j] = true;
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
小B: 这样我们就完成目标了
小A: 不,还有一些细节。首先调用函数时应传入 \(n - 1\),而不是 \(n\);其次有一个特例,当 \(n=1\) 时,应输出1,因为他自己就站在这个格里,没有其他人
完整代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
bool vis[N];
int phi[N];
void esieve(int n)
{
for(int i = 1; i <= n; i ++)
{
phi[i] = i;
}
for(int i = 2; i <= n; i ++)
{
if(!vis[i])
{
for(int j = i; j <= n; j += i)
{
vis[j] = true;
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
int main()
{
int n;
cin >> n;
esieve(n - 1);
int ans = 0;
for(int i = 1; i <= n - 1; i ++)
{
ans += phi[i];
}
if(n == 1)
{
cout << 0;
return 0;
}
cout << ans * 2 + 1;
return 0;
}
hello, I'm yuzihang, if you need to copy this, please quote this url: https://www.cnblogs.com/yuzihang/articles/17003202.html

浙公网安备 33010602011771号