BZOJ2190: [SDOI2008]仪仗队

Description

  作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N *N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
太神了
  现在,C君希望你告诉他队伍整齐时能看到的学生人数。

Input

  共一个数N。

Output

  共一个数,即C君应看到的学生人数。

Sample Input

  4

Sample Output

  9

HINT

【数据规模和约定】   对于 100% 的数据,1 ≤ N ≤ 40000

Source

数论

以左下角为原点建立座标系,显然gcd(x,y)=1 时就能看见(若gcd(x,y)=k(k1) ,则(x,y) 一定会被(x/k,y/k) 挡住),那么只需要求出i=1n1φ(i)2+1 即可(欧拉函数)(左右对称,再加上对角线的那一条)。
一开始很傻逼的程序:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,ans=0;
inline void read(int &x){
    char t=getchar();
    int f=1;x=0;
    while ((t<48)or(t>57)){if(t=='-')f=-1;t=getchar();}
    while ((t>=48)and(t<=57)){x=x*10+(int)t-48;t=getchar();}
    x*=f;
}
int phi(int n)
{
    int ans=1;
    for (int i=2;i*i<=n;++i)
    if (n%i==0)
    {
        n/=i;
        ans*=(i-1);
        while (n%i==0)
        {
            n/=i;
            ans*=i;
        }
    }
    if (n>1) ans*=(n-1);
    return ans;
}
int main()
{
    read(n);//pascal的感觉……
    for (int i=1;i<=n-1;++i) ans+=phi(i);
    printf("%d",ans*2+1);
    return 0;
}

来自黄学长的正解:

#include<iostream>
#include<cstdio>
#define N 40000
using namespace std;
int n;
int phi[40005],prime[40005],tot,ans;
bool mark[40005];
void getphi()
{  
   int i,j;
   phi[1]=1;
   for(i=2;i<=N;i++)
   {
       if(!mark[i])  {prime[++tot]=i;phi[i]=i-1;}
       for(j=1;j<=tot;j++)
       {
          if(i*prime[j]>N)  break;
          mark[i*prime[j]]=1;
          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()
{
    scanf("%d",&n);
    getphi();
    for(int i=1;i<n;i++)
       ans+=phi[i];
    printf("%d",2*ans+1);
    return 0;
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章