复习一波反演。
非常粗暴的就是F(1)+2。
注意范围应该是n-1,因为在坐标系上,只有在原点看,点(1,2)才会挡住(2,4),最后加2就是上面和右边的两个点。
然而今天在caioj闲逛的时候发现了另外一种做法,就是用phi,抽象一下,设当前点为(x,y)那么应该xy互质才可以看到
(代码写得很丑,思路不是很清晰)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int pr,prime[41000],u[41000]; bool v[41000]; void mobius_inversion() { pr=0;u[1]=1; memset(v,true,sizeof(v)); for(int i=2;i<=40000;i++) { if(v[i]==true) { prime[++pr]=i; u[i]=-1; } for(int j=1;j<=pr&&i*prime[j]<=40000;j++) { v[i*prime[j]]=false; if(i%prime[j]==0){u[i*prime[j]]=0;break;} u[i*prime[j]]=-u[i]; } u[i]+=u[i-1]; } } int getF(int n) { int F=0,last; for(int d=1;d<=n;d=last+1) { last=n/(n/d); int G=(n/d)*(n/d); F+=(u[last]-u[d-1])*G; } return F; } int main() { mobius_inversion(); int n; scanf("%d",&n); printf("%d ",getF(n-1)+2); return 0; }
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int phi[41000],pr,prime[41000]; bool v[41000]; void getprime() { pr=0;phi[1]=1; memset(v,false,sizeof(v)); for(int i=2;i<=40000;i++) { if(v[i]==false) { prime[++pr]=i; phi[i]=i-1; } for(int j=1;j<=pr&&i*prime[j]<=40000;j++) { v[i*prime[j]]=true; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } int main() { getprime(); int n; scanf("%d",&n);n--; int ans=0; for(int i=1;i<=n;i++)ans+=phi[i]; printf("%d ",ans*2+1); return 0; }