题目链接:https://vjudge.net/problem/CodeForces-546D
题意:
给一个数n=a!/b!,求这个数n质因数分解后,质因数的个数之和。
思路:
a, b的范围是(1 ≤ b ≤ a ≤ 5 000 000),可以先枚举[1, sqrt(a)]内的素数,然后用这些素数对[a, b]范围内的数进行筛选。由于t太大,需要求前缀和。
和这题类似: hdu6069
总结:
比赛时写到这题,我知道和hdu6069这道多校类似,但是当时我还没补题,瞬间GG…
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn = 5e6 + 100;
bool valid[maxn];
int ans[maxn], tot;
ll mp[maxn], d[maxn], pre[maxn];
void getPrime(int n, int &tot, int ans[]){
tot = 0;
memset(valid, true, sizeof(valid));
valid[0] = valid[1] = false;
for(int i=2; i<=n; ++i){
if(valid[i]){
ans[++tot] = i;
}
for(int j=1; ((j<=tot)&&(i*ans[j]<=n)); ++j){
valid[i*ans[j]] = false;
if(i%ans[j]==0) break;
}
}
}
void getAnswer(ll l, ll r){
for(ll i=l; i<=r; ++i){
d[i-l] = 0;
mp[i-l] = i;
}
d[0] = 1;
for(int i=1; i<=tot; ++i){
ll idx = l / ans[i] + (l%ans[i]==0?0:1);
idx = idx * ans[i];
while(idx <= r){
ll cnt = 0;
while(mp[idx-l] % ans[i] == 0){
mp[idx-l] /= ans[i];
++cnt;
}
d[idx-l] += cnt;
idx += ans[i];
}
}
pre[0] = 0;
for(ll i=0; i<=r-l; ++i){
if(mp[i]==1)
pre[i+1] += (d[i]+pre[i]);
else
pre[i+1] += (d[i]+1+pre[i]);
}
}
int main(){
ll t, l, r;
scanf("%lld", &t);
getPrime(maxn-5, tot, ans);
getAnswer(1, 5000005);
while(t--){
scanf("%lld%lld", &l, &r);
printf("%lld\n", pre[l]-pre[r]);
}
return 0;
}