UOJ传送门
题目描述
这里是跳蚤国中央广播电台,现在为您转播的是著名人类智慧大师 picks 博士与人工智能 betacome 之间的最后一轮赛事。
这一场交锋的规则由网友 st****ll 提供,这位网友也将获得由不想跳的跳蚤不是好跳蚤——最强跳蚤跳跳跳公司提供的金牌跳蚤一只。
就在刚才,第二轮比赛也已经结束了,picks 博士不负众望为人类扳回了一城。特别是在刚才劣势的时候,picks 博士突然地停止了对盘子的操作,让 betacome 乱了阵脚,并最后实现了反超,这一手操作也被网友戏称为“神之一手”。
“恩,这一手表明了 betacome 也是存在弱点而不是不可战胜的,picks 博士可能也在一直尝试着不同的比赛风格,试图找到 betacome 的漏洞。上一场的胜利说明了 betacome 在对于突发事件的应对方式可能存在着缺陷,在这一轮 picks 博士应该会针对这一点进行比赛,我认为他的胜率应该会非常大。”
那看来 A 先生抱着非常乐观的心态啊,现在最后一轮的比赛已经开始了,同样,接下来由 A 先生来给我们介绍一下这一轮比赛的规则。
“好,大家现在看屏幕,在这一轮游戏中,给出了一个如下所示的将 n n n 分解质因子的算法。”
- 检查 n n n是否是质数,假如 n n n是质数或 n = 1 n=1 n=1则直接结束。
- 定义一个变量 p p p,初始值为 2 2 2。
- 检查 p p p是否是 n n n的因子,假如 p p p是 n n n的因子,不断将 n n n除去 p p p,直到 p p p不再是 n n n的质因子。
- 检查 n n n是否是质数,假如 n n n是质数或 n = 1 n=1 n=1,就结束这个算法,否则将 p p p的值加一,返回第三步。
“为了检验人类智慧和人工智能之间的计算能力的差距,主办方希望选手对区间 [ l , r ] [l,r] [l,r] 中的所有数都用这个算法进行分解。为了检验计算的正确性,选手需要计算分解完每一个数后, p p p的和。特殊地,如果分解在第一步就结束了,那么就认为 p = 0 p=0 p=0。”
恩,谢谢 A 先生。大家可以看到这一道是数论方面的题目,刚才 A 先生也私下和我说了,这一道题目的难度要比前两轮的难度高很多,他认为在短时间内,比赛双方都无法得到准确的结果。因为我们节目组决定与观众们进行互动,正在收看节目的观众可以关注节目跳蚤信公众号参与解题,最快得到正确答案的观众将会获得由不想跳的跳蚤不是好跳蚤——最强跳蚤跳跳跳公司提供的精美礼品一份。
作为一名光荣的吃土少年,你立志要把这份礼品收入囊中以告别悲惨的吃土生活。然而,全世界的观众中也不乏人类智慧大师的存在,为了从他们中脱颖而出,你需要以最快的速度得到这一个问题的答案。
输入输出格式
输入格式
第一行两个正整数 l , r l,r l,r,表示需要分解的数的范围。
输出格式
输出一行一个整数,表示每次分解结束时,变量 p p p 的值之和。
C/C++ 输入输出 long long 时请用 %lld
。
输入输出样例
输入样例#1:
16 20
输出样例#1:
7
输入样例#2:
35 3657
输出样例#2:
23333
输入样例#3:
10000002333 10002333333
输出样例#3:
5346939605
限制与约定
测试点编号 | 限制与约定 |
---|---|
1 | r ≤ 1 0 4 r≤10^4 r≤104 |
2 | r ≤ 1 0 7 r≤10^7 r≤107 |
3 | r ≤ 1 0 9 r≤10^9 r≤109, r − l ≤ 1 0 7 r−l≤10^7 r−l≤107 |
4 | r ≤ 1 0 10 r≤10^{10} r≤1010, r − l ≤ 1 0 7 r−l≤10^7 r−l≤107 |
5 | r ≤ 3 × 1 0 10 r≤3×10^{10} r≤3×1010, r − l ≤ 1 0 7 r−l≤10^7 r−l≤107 |
6 | r ≤ 5 × 1 0 10 r≤5×10^{10} r≤5×1010 |
7 | r ≤ 7 × 1 0 10 r≤7×10^{10} r≤7×1010 |
8 | r ≤ 8 × 1 0 10 r≤8×10^{10} r≤8×1010 |
9 | r ≤ 9 × 1 0 10 r≤9×10^{10} r≤9×1010 |
10 | r ≤ 1 0 11 r≤10^{11} r≤1011 |
对于所有数据, 1 ≤ l ≤ r 1≤l≤r 1≤l≤r, l + r ≤ 1 0 11 l+r≤10^{11} l+r≤1011。
解题分析
其实题目就是让我们求每个数的次大质因数, 联想到我们min25筛的时候也是要枚举一个最小的因数, 因此我们在统计$S(n,k) 的 时 候 就 会 对 的时候就会对 的时候就会对k-1$大的质数产生贡献。直接统计即可。
注意 f ( p k ) = p f(p^k)=p f(pk)=p。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 1005000
int pcnt, pos, sqr, dif;
int pri[MX], id1[MX], id2[MX];
bool npr[MX];
ll val[MX], f[MX];
void Sieve_prime()
{
int tar;
for (R int i = 2; i < MX; ++i)
{
if (!npr[i]) pri[++pcnt] = i;
for (R int j = 1; j <= pcnt; ++j)
{
tar = i * pri[j];
if (tar >= MX) break;
npr[tar] = true;
if (!(i % pri[j])) break;
}
}
}
void Sieve(R ll n)
{
ll buf, tar;
dif = 0; sqr = std::sqrt(n);
pos = std::lower_bound(pri + 1, pri + 1 + pcnt, sqr) - pri;
if (pri[pos] > sqr) --pos;
for (R ll lef = 1, rig; lef <= n; lef = rig + 1)
{
val[++dif] = n / lef;
rig = n / val[dif];
if (val[dif] <= sqr) id1[val[dif]] = dif;
else id2[n / val[dif]] = dif;
f[dif] = val[dif] - 1;
}
for (R int j = 1; j <= pos; ++j)
{
for (R int i = 1; i <= dif && 1ll * pri[j] * pri[j] <= val[i]; ++i)
{
buf = val[i] / pri[j];
if (buf <= sqr) tar = id1[buf];
else tar = id2[n / buf];
f[i] = f[i] - f[tar] + j - 1;
}
}
}
ll S(R ll n, R ll up, R int k)
{
if (up <= 1 || pri[k] > up) return 0;
ll buf, tar, ret;
tar = up <= sqr ? id1[up] : id2[n / up];
ret = 1ll * pri[k - 1] * (f[tar] - k + 1);
for (R int i = k; i <= pos; ++i)
{
buf = pri[i], tar = buf * pri[i];
if (tar > up) break;
for (; tar <= up; buf = tar, tar *= pri[i])
ret += S(n, up / buf, i + 1) + pri[i];
}
return ret;
}
ll solve(R ll n)
{
Sieve(n);
return S(n, n, 1);
}
int main(void)
{
ll lef, rig; Sieve_prime();
scanf("%lld%lld", &lef, &rig);
printf("%lld", solve(rig) - solve(lef - 1));
}