bzoj 2190: [SDOI2008]仪仗队

2190: [SDOI2008]仪仗队

Description

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

Input

  共一个数N。

Output

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

Sample Input

  4

Sample Output

  9

HINT

【数据规模和约定】   

对于 100% 的数据,1 ≤ N ≤ 40000

题解:

n^2的枚举应该是很好写的,先把所有的点都连线,枚举点的坐标,判断gcd(i,j)的值,若大于1即表示中间有点在连线之间

#include<stdio.h>
#include<iostream>
using namespace std;
int n,i,j,ans;
int gcd(int a,int b)
{
    if(b==0) return a;
    if(a%b==0) return b;else gcd(b,a%b);
}
int main()
{
    scanf("%d",&n);
    ans=n*n-1;
    for(i=0;i<n;i++)
     for(j=0;j<n;j++)
        if(i!=0||j!=0)
    {
        if(gcd(i,j)-1) ans--;
    }
    cout<<ans;
    return 0;
}

首先j可以只枚举小于等于i的部分,再乘2(注意i==j的情况)

那么对于当前i的答案就是总数减去与i互质的个数(用欧拉函数)

#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
int n,i,j,k,ans,sum,p[40005],a[40004];
int gcd(int a,int b)
{
    if(b==0) return a;
    if(a%b==0) return b;else gcd(b,a%b);
}
int main()
{
    scanf("%d",&n);
    p[1]=1;
    for(i=2;i<=n;i++)
    if(p[i]==0)
     for(j=2;j<=n/i;j++)
     p[i*j]=1;
    ans=n*n-1;
    for(i=2;i<n;i++)
    {
        k=0;
        for(j=1;j<=(int)(sqrt(i));j++)
            if(i%j==0)
        {
            if(p[j]==0)
            {
                k++;
                a[k]=j;
            }
            if(i/j!=j&&p[i/j]==0)
            {
                k++;
                a[k]=i/j;
            }
        }
        sum=i;
        for(j=1;j<=k;j++)
            sum=sum*(a[j]-1)/a[j];
        sum=i-sum;
        ans-=sum*2+1;
    }
    cout<<ans;
    return 0;
}

 

posted @ 2016-05-10 20:55  lwq12138  阅读(148)  评论(0编辑  收藏  举报