做题总结——Fear Factoring

做题总结——Fear Factoring


原题

在这里插入图片描述

题意分析:

这道题目题意很简单,就是求出[a,b]区间内所有数的因数之和

做题思路:

开始自己的做法是特别愚蠢的 暴力破解法,也就是分别枚举[a,b]区间里每一个数的因数,最后累加起来,可想而知这种做法肯定是不对的。后面听了学长的讲解,这道题一共有两种思路。

  • 枚举从1到sqrt(b)的每一个数i,求出[a,b]能够以i作为因数的最小的那个数,这样就可以得到[a,b]区间内所有可以以i为因数的数,再进行累加即可
  • 利用数论分块的方法,具体分析参考数论分块解决

代码实现

1、暴力破解法:

//利用暴力破解法
#include <bits/stdc++.h>
using namespace std;
int main()
{
    
    
    long long a, b, i;
    while (cin >> a >> b)
    {
    
    
        long long ans=0;
        for (i = 1; i * i <= b; i++)
        {
    
    
            long long d = (a / i) * i;    //求出[a,b]内第最小的能够以i作为因数的数
            while (d < a  || i*i>d)      //如果求出的d小于a或者原来已经求过因数了,取下一个能够以i为因数的(也就是d+i)
            {
    
    
            	d+=i;
            }
            for (d; d <= b; d += i)      //累加因数
            {
    
    
                ans += i;               
                if (i < d / i)          //这里的判断防止累加重复了
                {
    
    
                    ans += d / i;
                }
            }
        }
        cout << ans << endl;
    }
    //system("pause");
    return 0;
}

2、数论分块法

//利用数论分块的思想解决该问题
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;    //这里不用unsigned long long无法AC
ll sol(ll n)
{
    
    
    ll ans=0;
    ll r;
    for(ll l=1;l<=n;l=r+1)  //枚举因数,同时更新区间的右端点
    {
    
    
        ll s=n/l;  //s是从1到n中含因数l的数的个数
        r=n/s;   //[l,r]中的每一个数能作为从1到n中s个数的因数(相当于求分块区间的右端点)(这里描述不太准确,以后想明白再修改)
        ans+=(l+r)*(r-l+1)/2*s;     //[l,r]作为因数的贡献,相当于求一个等比数列的值
    }   
    return ans;
}
int main()
{
    
    
    ll a,b;
    while((scanf("%llu%llu", &a, &b)!=EOF))
    {
    
    
        cout<<sol(b)-sol(a-1)<<endl;
    }
    //system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_46772594/article/details/108049827