洛谷传送门
BZOJ传送门
题目背景
九条可怜是一个富有的女孩子。
题目描述
她长大以后创业了,开了一个公司。 但是管理公司是一个很累人的活,员工们经常背着可怜偷懒,可怜需要时不时对办公室进行检查。
可怜公司有 n n n 个办公室,办公室编号是 l l l 到 l + n − 1 l+n-1 l+n−1 ,可怜会事先制定一个顺序,按照这个顺序依次检查办公室。一开始的时候,所有办公室的员工都在偷懒,当她检查完编号是 i i i 的办公室时候,这个办公室的员工会认真工作,并且这个办公室的员工通知所有办公室编号是 i i i 的倍数的办公室,通知他们老板来了,让他们认真工作。因此,可怜检查完第 i i i 个办公室的时候,所有编号是 i i i 的倍数(包括 i i i )的办公室的员工会认真工作。
可怜发现了员工们通风报信的行为,她发现,对于每种不同的顺序 p p p ,都存在一个最小的 t ( p ) t(p) t(p) ,使得可怜按照这个顺序检查完前 t ( p ) t(p) t(p) 个办公室之后,所有的办公室都会开始认真工作。她把这个 t ( p ) t(p) t(p) 定义为 p p p 的检查时间。
可怜想知道所有 t ( p ) t(p) t(p) 的和。
但是这个结果可能很大,她想知道和对 1 0 9 + 7 10^9+7 109+7 取模后的结果。
输入输出格式
输入格式:
第一行输入两个整数 l , r l,r l,r 表示编号范围,题目中的 n n n 就是 r − l + 1 r-l+1 r−l+1 。
输出格式:
一个整数,表示期望进行的轮数。
输入输出样例
输入样例#1:
2 4
输出样例#1:
16
说明
样例解释
考虑所有办公室被检查的相对顺序:
{2 3 4} ,时间是 2 。 {3 2 4} ,时间是 2 。 {4 2 3} ,时间是 3 。 {4 3 2} ,时间是 3 。 {2 4 3} ,时间是 3 。 {3 4 2} ,时间是 3 。
和是 16 16 16 。
数据范围
对于 20% 的数据,
r
−
l
+
1
≤
8
r-l+1\leq 8
r−l+1≤8。
对于另 10% 的数据,
l
=
1
l=1
l=1。
对于另 10% 的数据,
l
=
2
l=2
l=2。
对于另 30% 的数据,
l
≤
200
l\leq 200
l≤200。
对于 100% 的数据,
1
≤
l
≤
r
≤
1
0
7
1\leq l\leq r\leq 10^7
1≤l≤r≤107。
解题分析
显然有一些办公室必须到达一次, 我们用埃氏筛法筛出来这些位置, 然后讨论最靠右的一个关键办公室的位置, 乘上组合数就好了。
总复杂度 O ( n l n ( l n ( n ) ) ) O(nln(ln(n))) O(nln(ln(n)))。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <string>
#include <iostream>
#include <cstring>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 10050000
#define MOD 1000000007ll
#define ll long long
int tot, lef, rig, n;
bool vis[MX];
int ans, inv[MX];
using namespace std;
void get()
{
for (R int i = lef; i <= rig; ++i)
{
if (!vis[i])
{
++tot;
for (R int j = i << 1; j <= rig; j += i)
vis[j] = true;
}
}
inv[0] = inv[1] = 1;
for (R int i = 2; i <= 1e7; ++i) inv[i] = 1ll * inv[MOD % i] * (MOD - MOD / i) % MOD;
}
int main(void)
{
int fac, ans;
scanf("%d%d", &lef, &rig);
get(); fac = 1; n = rig - lef + 1;
for (R int i = tot; i >= 2; --i) fac = 1ll * fac * i % MOD;
ans = fac;
for (R int mul = tot + 1; mul <= n; ++mul)
fac = 1ll * fac * mul % MOD * inv[mul - tot] % MOD, ans = (ans + fac) % MOD;
ans = 1ll * ans * tot % MOD;
n = n - tot; fac = 1;
for (R int i = 2; i <= n; ++i) fac = 1ll * fac * i % MOD;
cout << 1ll * ans * fac % MOD;
}