一个合数的真因数是指这个数不包括其自己的全部因数,ios
例如 6 的正因数有1, 2, 3, 6,其中真因数有 1, 2, 3。git
一个合数的最大真因数则是这个数的全部真因数中最大的一个,例如 6 的最大真因数为 3。spa
给定正整数 l 和 r,请你求出 l 和 r 之间(包括 l 和 r)全部合数的最大真因数之和。3d
输入共一行,包含两个正整数 l 和 r。保证 l ≤ r。code
输出共一行,包含一个整数,表示 [l,r] 内全部合数的最大真因数之和。blog
1 10ip
17get
【样例 1 解释】input
在 1 至 10 之间的合数有 4, 6, 8, 9, 10,string
它们的最大真因数分别为 2, 3, 4, 3, 5,
所以最大真因数之和为 2 + 3 + 4 + 3 + 5 = 17。
【样例 2 输入】
101 1000
【样例 2 输出】
163446
【样例 3 输入】
180208 975313
【样例 3 输出】
151642139152
【样例 4 输入】
339762200 340762189
【样例 4 输出】
112318862921546
【样例 5 输入】
2500000000 5000000000
【样例 5 输出】
3094668961678105770
要求合数的最大真因数,至关于求合数除以其最小质因子。
再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; }