[SDOI] 仪仗队

SDOI仪仗队

迎面冷风袭来

​ 我又该何去何从

​ 哪里

​ 是我的安居之处

正文

我们这个题有一个是很显然的想法,我们可以想到是跟 \(\gcd\) 有关,事实上没有任何分析的,我们就可以得到36分的高分

注意点如下:

  • 0-n-1 编号,特判 i=0 的时候
  • 对于一个点 (i,j) 其中 i,j>0 我们当且仅当 \(gcd(i,j)=1\)时,这个点是看得到的,你可以认为是一个正比例函数

之后,检查每一个点,判断其 \(\gcd(i,j)=1\) 的是否,记录答案,这样只能拿27pts,但是已经不错了,重要的是,我们可以只检查一半的点就好了,剩下的一半乘二即可,这是一个常数的优化

#include <iostream>
#include <cstring> 
#include <cstdio>
using namespace std;
int n,ans;
int gcd(int a,int b){
    if(a<b) return gcd(b,a);
    if(a%b==0) return b;
    return gcd(b,a%b); 
}
int main(){
    scanf("%d",&n);
    if(n==1){printf("0");return 0;}
    for(int i=0;i<n;i++){
        if(i==0){
            ans++;
            continue;
        }
        for(int j=i+1;j<n;j++)
            if(gcd(i,j)==1){
                ans++;
            }
    }
    ans=ans<<1;
    ans++;
    printf("%d",ans); 
    return 0;
}

我们这里使用欧几里得的算法

然后,我们来考虑正解。咋办?我们考虑一个东西
\[ \forall n,m \in N^+ , 若对于所有的 i \in [1,n],j \in [1,m],且 i,j有一个公约数是k,这样的i,j,有 \lfloor \frac{n}{k} \rfloor \times \lfloor \frac{m}{k} \rfloor 对 \]
而这个结论几乎是显然的,所以我们考虑容斥原理,只要求出所有的公约数,然后一减就好了

当然了,我们令 \(f[i]\) 为最大公约数是 i 的对数,当然了,这就要减一个后面 i 的倍数的 f ,最后 \(f[1]\) 即为所求

所以,我们可以得到,一个算法时间复杂度为 \(O(n \log n)\)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=44000;
int n,f[Maxn],ans;

int main(){
    scanf("%d",&n);
    if(n==1){printf("0");return 0;}
    n--;
    ans=n*n;
    for(int i=n;i>=2;i--){
        int tmp=(n/i)*(n/i);
        for(int k=2;k<=n/i;k++){
            tmp-=f[k*i];
        }
        f[i]=tmp;
        ans-=f[i];
    }
    printf("%d",ans+2);
    return 0;
}

但是因为没有算 00 列的两个,所以答案加二

我还是

​ 回到,一横一竖的生活

猜你喜欢

转载自www.cnblogs.com/zhltao/p/12345100.html