• 【框架编程思想】线数筛的高级应用(欧拉12题和欧拉21题)


    题意:求解因子个数大于500的三角数

    方法一:
    约数个数定理:

    时间复杂度:O(N^3)

    #include <bits/stdc++.h>
    using namespace std;
    
    int64_t GetNumFac(int64_t x)
    {
        int64_t ans = 1;
        //cout<< x ;
        for (int64_t i=2; i  <= x; i++)
        {
            if (x % i)continue;
            int times = 0;
            while (x % i == 0)
            {
                x  /= i;
                times ++;
            }
            ans *= (times + 1);
        }
        //cout<<"  **  "<<ans<<endl;
        return ans;
    }
    int main()
    {
        int64_t n = 1;
        while (1)
        {
            if (n&1)
            {
                if (GetNumFac(n) * GetNumFac((n+1)/2) >= 500) break;
            }
            else
            {
                if(GetNumFac(n/2) * GetNumFac((n+1)) >= 500)  break;
            }
            n++;
        }
        printf("%lld
    ",n*(n + 1 )/2);
        return 0;
    }
    
    

    方法二:
    要点1:线性筛的应用——用24 和 2 标记48的约数个数
    48 = 2^4 * 3^1 num[48] = (4+1)2=10
    24 = 2^3 * 3^1 num[24] =(3+1)
    2= 8
    模拟:
    amt[48] = num[24] / (min_pow[i] + 1) * (min_pow[prime[j] * i] + 1);
    amt[48] = num[24] / (min_pow[i] + 1) * (min_pow[i] + 2);
    注意:prime[j] * i 和 i 的最小因子的幂次数一定相差,这个最小的因子一定是prime[j]
    中心思想实现用 24 和 2 表示 48的因子个数
    要点2:关于三角数的约数规律

    时间复杂度:O(N)
    代码实现:

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX_N = 1e6;
    
    int amt[MAX_N+5] = {0};       ///约数个数
    int prime[MAX_N + 5] = {0};   ///中间保存素数
    int min_pow[MAX_N + 5] = {0}; /// 保存 最小素因子的幂次数+1
    
    int Get_Trinum(int x)
    {
        return x * ( x + 1 ) / 2;
    }
    
    void Init_NumOfPrime()
    {
        for (int i=2; i <= MAX_N; i++)
        {
            if (!prime[i])
            {
                prime[++prime[0]] = i;
                amt[i] = 2;
                min_pow[i] = 1;
            }
            for (int j=1; j <= prime[0]; j++)
            {
                int tmp = i * prime[j];
                if (tmp > MAX_N) break;
                prime[tmp ] = 1;
                if (i % prime[j]) 
                {
                    min_pow[ tmp ] =  1;
                    amt[tmp] = amt[i] * amt[prime[j]];
                }
                else
                {
                    min_pow[tmp ] = min_pow[i] + 1;
                    amt[tmp ] = amt[i] / (min_pow[i] + 1 ) * (min_pow[tmp] + 1);
                    break;///注意 : break原因 :我们这个题只需要更新最小素因子的幂次数,在不2 和 24 互素的情况下,48最小素因子的幂次数已经更新了
                }
            }
        }
        return ;
    }
    
    int main()
    {
        Init_NumOfPrime();
        int n = 1;
        while (1)
        {
            if (n&1)
            {
                if (amt[n] * amt[(n+1)/2] >= 500) break;
            }
            else
            {
                if(amt[n/2] * amt[n+1] >= 500) break;
            }
            n++;
        }
        printf("%d
    ",Get_Trinum(n));
        return 0;
    }
    

    总结

    变形应用:


    题意:定义: a的约数和(不包括本身)等于b,b的约数和(不包括本身)等于a,a,b互为基佬数,求10000以内的基佬数的和
    要点:找出约数和与约数定理的关系简化运算

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX_N = 1e6;
    const int N = 1e4;
    
    int sum[MAX_N+5] = {0};       ///约数个数
    int prime[MAX_N + 5] = {0};   ///中间保存素数
    int min_pow[MAX_N + 5] = {0}; /// 保存 q^n
    
    void Init_SumOfPrime()
    {
        for (int i=2; i <= MAX_N; i++) ///注意:
        {
            if (!prime[i])
            {
                prime[++prime[0]] = i;
                sum[i] = 1 + i;
                min_pow[i] = i * i ;
            }
            for (int j=1; j <= prime[0]; j++)
            {
                int tmp = i * prime[j];
                if (tmp > MAX_N) break;
                prime[tmp ] = 1;
                if (i % prime[j])
                {
                    min_pow[ tmp ] =  prime[j] * prime[j];
                    sum[tmp] = sum[i] * sum[prime[j]];
                }
                else
                {
                    min_pow[tmp] = min_pow[i] * prime[j];
                    sum[tmp] = sum[i] * ( min_pow[tmp] - 1 ) / (min_pow[i] - 1 );
                    break;
                }
            }
        }
        return ;
    }
    
    int main()
    {
        Init_SumOfPrime();
        int ans = 0;
        for (int i = 2; i <= N; i++)
        {
            int num1 = sum[i] - i;
            int num2 = sum[num1] - num1;
            if (i == num2 && num1 <= N && num2 <= N && num1 != i)
            {
                ans += i;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    practice
    C#Hello World
    Merge
    Python学习面向对象编程
    Python学习Python操作数据库
    jmeter压力测试
    Python学习基础常用模块
    Python学习Python操作excel
    Python学习网络编程
    Python学习函数
  • 原文地址:https://www.cnblogs.com/sxy-798013203/p/7824408.html
Copyright © 2020-2023  润新知