BZOJ-2190 仪仗队 数论+欧拉函数(线性筛)

今天zky学长讲数论,上午水,舒爽的不行。。后来下午直接while(true){懵逼;}死循全程懵逼。。。。(可怕)Thinking Bear。

2190: [SDOI2008]仪仗队
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 2092 Solved: 1325
[Submit][Status][Discuss]

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

Input
共一个数N。

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

Sample Input
  4

Sample Output
  9

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

Source
数论

这道题啊,算是我懵逼过程中最水的题了。。于是下课 顺利一遍水过(哦,第一次复制错了。。。CE。。不算!)

这道题,先小数据捯饬捯饬。。发现了规律:
1.除了坐标带0的点,其他的点都满足gcd(x,y)=1,所以累加欧拉函数φ。。然后加上坐标带0的点即可(2个,一成不变)。。
2.然后发现具有对称性。。于是只需要搞上方的三角即可。但是对角线那个点重复了一次所以-1

于是 ans=Σ(φ【1..n-1】)*2+1(+1其实是+2-1)
ps(程序里,欧拉函数的处理没有处理φ【1】所以有个初始值。。思路一样。。)

那么就是筛出欧拉函数即可。。(根据性质:)
性质① m是素数时,有φ(m)=m-1
性质② 当m、n互素时,φ(m*n)=φ(m)*φ(n)
性质③ 对一切正整数n,有φ(p^n)=[p^(n-1)]*(p-1)

奇怪的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 40010
long long prime[maxn],phi[maxn];
bool flag[maxn]={0};
int n;
long long ans;

void get_phi()
{
    memset(flag,0,sizeof(flag));
    flag[1]=1; 
    int cnt=0;
    for (int i=2; i<=maxn; i++)
        {
            if (!flag[i])
                prime[cnt++]=i,phi[i]=i-1;
            for (int j=0; j<cnt && i*prime[j]<maxn; j++)
                {
                    flag[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);
    get_phi();
    ans=2; 
    for (int i=2; i<n; i++)
        ans+=phi[i];
    printf("%lld",ans*2-1);
    return 0;
}
posted @ 2016-02-14 19:15  DaD3zZ  阅读(234)  评论(0编辑  收藏  举报