【FJWC2018】最大真因数

题面

Description

一个合数的真因数是指这个数不包括其本身的所有因数,

例如 6 的正因数有1, 2, 3, 6,其中真因数有 1, 2, 3。

一个合数的最大真因数则是这个数的所有真因数中最大的一个,例如 6 的最大真因数为 3。

给定正整数 l 和 r,请你求出 l 和 r 之间(包括 l 和 r)所有合数的最大真因数之和。

Input

输入共一行,包含两个正整数 l 和 r。保证 l ≤ r。

Output

输出共一行,包含一个整数,表示 [l,r] 内所有合数的最大真因数之和。

Sample Input

1 10

Sample Output

17

【样例 1 解释】

在 1 至 10 之间的合数有 4, 6, 8, 9, 10,

它们的最大真因数分别为 2, 3, 4, 3, 5,

因此最大真因数之和为 2 + 3 + 4 + 3 + 5 = 17。

Hint

【样例 2 输入】

101 1000

【样例 2 输出】

163446

【样例 3 输入】

180208 975313

【样例 3 输出】

151642139152

【样例 4 输入】

339762200 340762189

【样例 4 输出】

112318862921546

【样例 5 输入】

2500000000 5000000000

【样例 5 输出】

3094668961678105770

img

题目分析

要求合数的最大真因数,相当于求合数除以其最小质因子。

再Min_25筛求素数和的过程中:
\[ g(n,j)= \begin{cases} g(n,j-1)&P_j^2> n\\ g(n,j-1)-f(P_j)\cdot[g(\frac{n}{P_j},j-1)-\sum_{i=1}^{j-1}f(P_i)]&P_j^2\leq n \end{cases} \]

其中
\[ g(\frac{n}{P_j},j-1)-\sum_{i=1}^{j-1}f(P_i) \]

求得的便是最小质因子为\(P_j​\)的合数之和。

我们只需在处理\(g\)的时候统计答案即可。

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#define MAXN 0x7fffffff
typedef unsigned long long LL;
const int N=250005;
using namespace std;
inline LL Getint(){register LL x=0,g=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')g=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*g;}
int prime[N],tot;bool vis[N];
LL sqr,w[N],g[N],sp[N];
int id1[N],id2[N],m;
void Pre(int n){
    for(int i=2;i<=n;i++){
        if(!vis[i])prime[++tot]=i,sp[tot]=sp[tot-1]+i;
        for(int j=1;j<=tot&&1ll*i*prime[j]<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}

LL Solve(LL n){
    tot=m=0;
    sqr=sqrt(n),Pre(sqr);
    for(LL i=1,j;i<=n;i=j+1){
        j=n/(n/i),w[++m]=n/i;
        g[m]=w[m]*(w[m]+1)/2-1;
        if(w[m]<=sqr)id1[w[m]]=m;else id2[j]=m;
    }
    LL ans=0;
    for(int j=1;j<=tot;j++){
        for(int i=1;i<=m&&(LL)prime[j]*prime[j]<=w[i];i++){
            int k=(w[i]/prime[j]<=sqr)?id1[w[i]/prime[j]]:id2[n/(w[i]/prime[j])];
            if(i==1)ans+=g[k]-sp[j-1];
            g[i]-=prime[j]*(g[k]-sp[j-1]);
        }
    }
    return ans;
}
int main(){
    LL l=Getint(),r=Getint();
    cout<<Solve(r)-Solve(l-1);
    return 0;
}

转载于:https://www.cnblogs.com/Emiya-wjk/p/10458344.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值