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

891120-20171112234911903-1568854093.png

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

方法一:
约数个数定理:
891120-20171112235449466-1344561965.png
时间复杂度: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*(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:关于三角数的约数规律

891120-20171117102601702-2111822721.png

时间复杂度: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\n",Get_Trinum(n));
    return 0;
}

总结

变形应用:

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

891120-20171117123310281-446860975.png

#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\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/sxy-798013203/p/7824408.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值