AcWing 201. 可见的点
题意:
题解:
我们先说结论:坐标(i,j),如果i和j互质,说明该坐标为可见
为什么?
我们想想什么样的坐标可见,什么样的会被挡住。光线是一个直线,在同一个直线上的点会被第一个点挡住,而所有光都从一个地方出发,也就是如果斜率一样,后面会被前面的挡住(暂时不考虑斜率不存在的情况)。对于坐标(i,j),斜率为k=i/j,如果i和j不互质,设gcd(i,j)=d,那么(i/d)/(j/d)也等于k,且(i/d,j/d)要比(i,j)小,前者会挡住后缀,这说明了i和j必须互质,不然会被更小的i/d和j/d给挡住
我们观察题目给的图形,图形是关于斜率为1的直线对称(也很好理解,x与y互质,那y也与x互质),因此我们只考虑下半部分
根据横坐标,我们依次查看,横坐标为1时,互质的点的数量为1,横坐标为2时,互质的数量为1…我们要找的是与横坐标互质,且小于横坐标的点的数量,这不就是欧拉函数吗
所有答案就是横坐标所对应的欧拉函数的和,乘2(因为我们只算了一半),加1(别忘了对称轴上还有一个点)
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=5e4+9;
int prime[maxn],cnt;
bool st[maxn];
int phi[maxn];
void init(int n){phi[1]=1;for(int i=2;i<=n;i++){if(!st[i]){prime[cnt++]=i;phi[i]=i-1;}for(int j=0;prime[j]*i<=n;j++){st[prime[j]*i]=1;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}phi[i*prime[j]]=phi[i]*(prime[j]-1);}}
}
int main()
{init(maxn-1);int n,m;cin>>m;for(int T=1;T<=m;T++){cin>>n;int res=1;//对角线那个 for(int i=1;i<=n;i++)res+=phi[i]*2;cout<<T<<" "<<n<<" "<<res<<endl; }return 0;
}