题意
给出一个n,每次画出一个(n,(−1)i+1∗i)(n,(−1)i+1∗i)的向量,一共画出n个这样的向量,求这个图形穿过了几个格点。
思路
通过观察我们可以发现每次画出(n,i)(n,i)的向量经过的格点数为gcd(i,n)gcd(i,n),所以答案为∑i=1ngcd(i,n)∑i=1ngcd(i,n),但是这样子做的话会超时。所以通过题解发现可以简化成∑d|nd∗φ(n/d)∑d|nd∗φ(n/d),我们可以只枚举到(√n)(n),然后用n/in/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)
}