18.09.09模拟赛T1。
一道数学题。
首先把对角线当成是某个点的移动轨迹,从左下到右上。
那么这个点每上升一个单位长度,就穿过一个格子。
每右移一个单位长度,也会穿过一个格子。
例外:穿过格点,会减少穿过的格子数。
初步的结论:R*C的矩形,对角线穿过的格子数N=R+C-gcd(R,C)。
那么我们只需算出这个方程的解的个数。
可以看出,R、C和gcd(R,C)都是gcd(R,C)的倍数。
那么N显然也是。
设N/gcd(R,C)=n,R/gcd(R,C)=r,C/gcd(R,C)=c。
方程两边同除gcd(R,C):n=r+c-1。
由欧几里得算法可得:gcd(n+1,r)=gcd(n+1-r,r)=gcd( (r+c-1) +1-r,r)=gcd(c,r)。
这时候r和c一定是互质的,假如它们有公因数,在除以gcd(R,C)时就会被除掉。
所以:gcd(r,c)=1。得:gcd(n+1,r)=1。
即:n+1与r互质,n是N得因数。
答案即为:
所以我们线性筛出从2到n+1的欧拉函数phi [ i ],挑出其中i-1是n的因数的,把它们的phi [ i ]加起来就行了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,cnt,ans; 7 int pr[100000005]; 8 bool v[100000005]; 9 int phi[100000005]; 10 11 int main() 12 { 13 scanf("%d",&n); 14 for(int i=2;i<=n+1;i++) 15 { 16 if(!v[i]) 17 { 18 pr[++cnt]=i; 19 phi[i]=i-1; 20 } 21 if(n%(i-1)==0)ans+=phi[i]; 22 for(int j=1;(j<=cnt)&&(i*pr[j]<=n+1);j++) 23 { 24 v[i*pr[j]]=true; 25 if(i%pr[j]==0) 26 { 27 phi[i*pr[j]]=phi[i]*pr[j]; 28 break; 29 }else 30 { 31 phi[i*pr[j]]=phi[i]*phi[pr[j]]; 32 } 33 } 34 } 35 printf("%d",(ans+1)/2); 36 return 0; 37 }