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;
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章