题意
给出一个n,每次画出一个 (n,(−1)i+1∗i) ( n , ( − 1 ) i + 1 ∗ i ) 的向量,一共画出n个这样的向量,求这个图形穿过了几个格点。
思路
通过观察我们可以发现每次画出
(n,i)
(
n
,
i
)
的向量经过的格点数为
gcd(i,n)
g
c
d
(
i
,
n
)
,所以答案为
∑i=1ngcd(i,n)
∑
i
=
1
n
g
c
d
(
i
,
n
)
,但是这样子做的话会超时。所以通过题解发现可以简化成
∑d|nd∗φ(n/d)
∑
d
|
n
d
∗
φ
(
n
/
d
)
,我们可以只枚举到
(√n)
(
n
)
,然后用
n/i
n
/
i
就可以得到另一个数了,完全平方数要特殊判断。具体原理不是很懂。
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
long long n,ans;
inline long long phi(long long n)//求欧拉函数
{
long long tot=n;
for (long long i=2;i<=sqrt(n);i++)
if (n%i==0)
{
tot=tot/i*(i-1);
while (n%i==0) n/=i;
}
if (n>1) tot=tot/n*(n-1);
return tot;
}
int main()
{
scanf("%lld",&n);
for (long long i=1;i<=sqrt(n);i++)
{
if (n%i==0)
{
ans+=i*phi(n/i);
if (i*i!=n) ans+=n/i*phi(i);
}
}
printf("%lld",ans+1);//加上起点(0,0)
}