【题意】
作为体育委员, C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N*N 的方阵,为了保证队伍在行进中整齐划一, C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
【思考历程】
想法:寻找每行(或每列)符合的点的个数规律,并注意观察其中gcd的情况。结果:并没有发现什么特别的规律,而且还出现了一些不知道怎么用gcd表示出来的结果。
【正解】
考虑到莫比乌斯反演是给到两个范围,求区间中gcd为k的组合的对数,
所以,观察什么样的点会被看到,什么样的点不会被看到。
发现:以c点为(0, 0)建立坐标系,当两点坐标互质时,会被看到。
换一种说法,横纵坐标之比相同(即正比例函数的k相同)的点在同一直线上。
【反思】
被遮住不就意味着在一条直线上吗?直线不就要构造直角坐标系吗?图形难道从(1,1)开始吗?
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int mo[40010];
int tot=0,prime[40010];bool v[40010];
void get_mo(int n)
{
mo[1]=1;
memset(v,true,sizeof(v));
for(int i=2;i<=n;i++)
{
if(v[i]==true)
{
prime[++tot]=i;
mo[i]=-1;
}
for(int j=1;j<=tot&&i*prime[j]<=n;j++)
{
v[i*prime[j]]=false;
if(i%prime[j]==0)
{
mo[i*prime[j]]=0;
break;
}
else
{
mo[i*prime[j]]=-mo[i];
}
}
}
}
void solve(int x,int y,int k)
{
x/=k;y/=k;
long long ans=2;//加上(0,1)和(1,0)两个包括0的点
for(int i=1;i<=y;i++)
{
ans+=(long long)mo[i]*(x/i)*(y/i);
}
printf("%lld\n",ans);
}
int main()
{
int n;
scanf("%d",&n);n--;//坐标系向下和向左各移1个单位
get_mo(n);
solve(n,n,1);
return 0;
}
推荐:《caioj1283 【莫比乌斯反演】GCD4》http://blog.csdn.net/a_bright_ch/article/details/78937191