仪仗队(容斥,欧拉,打表)

Description

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

Input

  共一个数N。

Output

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

Sample Input

  4

Sample Output

  9

Hint

 

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

 题解:典型的容斥题,但是看了网上的有人推出用欧拉也能做,还有用莫比乌斯函数做的。。。脑洞大开;莫比乌斯看不懂,欧拉容斥做了一遍,算是复习一下吧;由于是N*N所以可以用欧拉,最后是answer*2+1,这个他们说是看出来的。。。。。还是容斥可靠;

容斥:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<vector>
 7 using namespace std;
 8 typedef long long LL;
 9 vector<int>p;

10 void getp(int x){
11     p.clear();
12     for(int i=2;i*i<=x;i++){
13         if(x%i==0){
14             p.push_back(i);
15             while(x%i==0){
16                 x/=i;
17             }
18         }
19     }
20     if(x>1)p.push_back(x);
21 }
22 int getn(int x,LL n){
23     LL sum=0;
24     getp(x);
25     for(int i=1;i<(1<<p.size());i++){
26         LL temp=1,cnt=0;
27         for(int j=0;j<p.size();j++){
28             if(i&(1<<j)){
29                 temp*=p[j];cnt++;
30             //    printf("%d*",p[j]);
31             }
32         }
33     //    printf("\n");
34         if(cnt&1)sum+=n/temp;
35         else sum-=n/temp;
36     }
37     return n-sum;
38 }
39 int main(){
40     LL N;
41     while(~scanf("%lld",&N)){
42         N--;
43         LL ans=0;
44     //    getn(48,100)
45         for(int i=1;i<=N;i++){
46             ans+=getn(i,N);
47         //    printf("%lld\n",getn(i,N));
48         }
49         printf("%lld\n",ans+2);
50     }
51     return 0;
52 }

ouler:

LL ouler(LL n){
    LL p=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            p=p*(i-1)/i;
            while(n%i==0)n/=i;
        }
    }
    if(n>1)p=p*(n-1)/n;
//    printf("%lld\n",p);
    return p;
}
int main(){
    LL N;
    while(~scanf("%lld",&N)){
        LL ans=0;
        for(int i=1;i<N;i++){
            ans+=ouler(i);
        }
        printf("%lld\n",ans*2+1);
    }
    return 0;
}

欧拉打表:

const int MAXN=500005;
LL dp[MAXN];
void db(){
    dp[1]=1;
    for(int i=2;i<MAXN;i++){
        if(!dp[i]){
            for(int j=i;j<MAXN;j+=i){
                if(!dp[j])dp[j]=j;
//                dp[j]=dp[j]*(i-1)/i;
            }
        }
        dp[i]+=dp[i-1];
    }
}
int main(){
    db();
    LL N;
    while(~scanf("%lld",&N)){
        printf("%lld\n",2*dp[N-1]+1);
    }
    return 0;
}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值