• 题解 : 约数研究


    这是本蒟蒻第一次写题解,好激动。

    我下面介绍**四**种解法 _~~有两种比较神奇~~_

    ------------

    # 方法一

    先发一下正解吧,具体解释其他题解都有,我就不详细说了。重点是下面三种方法。
    ```cpp
    #include <iostream>
    using namespace std;
    typedef long long ll;

    ll n, ans;

    int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
    ans += n / i;
    }
    cout << ans << endl;
    return 0;
    }
    ```
    时间复杂度:O(n)~~应该是~~

    极其~~简陋~~精简,不是吗?

    ------------

    # 方法2

    但本蒟蒻考试的时候抽风了没有想到。

    这道题我看到题解里有许多巨佬已经把各种方法用上了,不过我要介绍一种方法,是当时我考模拟赛时想到的。那就是
    # ~~_打表_~~

    没错,你没有听错。我当时用暴力做只水了70分,我这时想到了我们机房的一位巨佬打表A了反素数,想着,干脆来一波打表吧~~感觉打表挺好玩的~~。

    思路:暴力的时间复杂度是O(n*$sqrt{n}$)~~打个根号打了5分钟才打出来,第一次写题解~~既然10^6的数据会炸。~~我们不如每10^5个数打一个表,然后暴力求解区间小于10^5的因数。~~

    _~~当时考试时我给老师看了一下我的方法,然后老师把嘴里的茶都吐了出来,说:~~_

    # 你这个毒瘤啊!

    打表生成器:

    ```cpp
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>

    #define maxa 1000001
    #define int long long
    using namespace std;

    int ans,n;
    int zhi[maxa],vis[maxa];
    void y(int x){
    int k=sqrt(x);
    for(int i=1;i<=k;i++){
    if(x%i==0)ans+=2;
    }
    if(x==k*k)ans--;
    }
    void fp(){
    for(int i=1;i<=n;i++){
    y(i);
    }
    }

    main(){
    cin>>n;
    fp();
    cout<<ans;
    }
    ```

    AC代码:

    ```cpp
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>

    #define maxa 1000001
    #define int long long
    using namespace std;

    int ans,n,m;
    int zhi[maxa],vis[maxa];
    int ans1[]={1166750,2472113,3829833,5221472,6638449,8075504,9529316,10997454,12478206,13970034};//传说中的打表
    void y(int x){
    int k=sqrt(x);
    for(int i=1;i<=k;i++){
    if(x%i==0)ans+=2;
    }
    if(x==k*k)ans--;
    }
    void fp(){
    for(int i=m;i<=n;i++){
    y(i);
    }
    }

    main(){
    cin>>n;
    if(n>=100000){
    ans+=ans1[(n/100000)-1];
    }
    m=n/100000;
    m*=100000;
    m++;
    fp();
    cout<<ans;
    }
    ```
    时间复杂度:O(n/10~~玄学的10~~*$sqrt{n/10}$)

    不过注意,如果你的测评~~姬~~机不好,可能有一个点会T。(999998)

    ------------

    # 方法三

    其实当时考试的时候我本来是用类似于素数筛的思想来做的,但是我WA了。我后来订正了一下。大概就是枚举每个数,如果有它的倍数,则ans+=2。平方数特判一下就可以了。

    代码:

    ```cpp
    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n,primes[1000005],pc=0,vis[1000005],cnt[1000005],ans;
    int main() {
    cin>>n;
    for(int i=1;i<=n;i++) cnt[i]=1;
    //素数筛
    for(int i=2;i<=n;i++) if(cnt[i]<=1) {
    primes[pc++]=i;
    for(int j=1;j*i<=n;j++) {
    vis[i*j]++;
    int tmp=j,c=2;
    while(tmp%i==0) tmp/=i,c++;
    cnt[i*j]*=c;
    }
    }
    for(int i=1;i<=n;i++) ans+=cnt[i];
    cout<<ans;
    }
    ```
    时间复杂度:O(nlogn).

    ------------

    # 方法四

    这种方法绝对是前无古人,后无来着的。因为这份代码是我们机房里的国家队卧底。他做到了传说中的
    # n方过百万,暴力碾标算!
    而且我们的老师重测了几遍,他的代码都跑的飞快,4~5ms,至多59ms。
    他正好避过了所有的数据。
    ## 他,就是
    # cpy大巨佬

    代码:
    (因为他太巨了,所以我怕这份代码吓坏洛谷。这里省略部分)

    ```
    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long long ans[1000005],anss=1,j=1;
    int main(){
    anss=1;
    cin>>n;
    for(int i=1;i<=n;i++) ans[i]=1;
    for(int i=2;i<=n;i++){
    //这里打上马赛克,因为他太巨了!
    j=1;
    }
    for(int i=2;i<=n;i++){
    anss+=ans[i];
    }
    cout<<anss;
    }
    ```

    时间复杂度: O(n^2)
    经实测,该算法实际速度和方法1不相上下。

    ------------
    以上就是本萌新的题解,这是我的第一个题解,写了两个多小时。还望各位神犇多多包容。

  • 相关阅读:
    php 将网页执行的输出写入到本地文件中
    网络爬虫技术
    解决:解压zip文件却变成cpgz文件
    SHA1算法实现及详解
    Mac配置PHP开发环境
    项目管理
    Oracle Primavera P6 R84单机版安装教程
    工时
    项目管理软件伙伴https://www.huobanyun.cn/
    Primavera 6.0
  • 原文地址:https://www.cnblogs.com/WQT-FFT/p/11266570.html
Copyright © 2020-2023  润新知