原题传送门
不是特别的难
最最最开始,令
n
=
r
−
l
+
1
n=r-l+1
n=r−l+1
20% n < = 8 n<=8 n<=8
我会暴力!
直接
O
(
n
!
∗
n
)
O(n!*n)
O(n!∗n)
10% l = 1 l=1 l=1
我会特判!
时间就是1的位置
所以答案是
(
n
−
1
)
!
∗
n
(
n
+
1
)
2
\frac{(n-1)!*n(n+1)}{2}
2(n−1)!∗n(n+1)
100%
我会推公式!
首先
l
=
1
l=1
l=1的情况直接特判掉
可以知道有那么一些数,不是任何
l
l
l~
r
r
r的数的倍数(除了自身)
如果把这些数选了,可以且仅可以完成任务
记这些数的个数为
s
u
m
sum
sum
sum可以用一个类似筛法的方法预处理出来
令
f
i
表
示
需
时
间
为
i
的
方
案
数
f_i表示需时间为i的方案数
fi表示需时间为i的方案数
f
i
=
P
n
−
s
u
m
n
−
i
∗
(
i
−
1
)
!
∗
s
u
m
=
(
n
−
s
u
m
)
!
∗
(
i
−
1
)
!
∗
s
u
m
(
i
−
s
u
m
)
!
f_i=P_{n-sum}^{n-i}*(i-1)!*sum=\frac{(n-sum)!*(i-1)!*sum}{(i-sum)!}
fi=Pn−sumn−i∗(i−1)!∗sum=(i−sum)!(n−sum)!∗(i−1)!∗sum
意义:
P
n
−
s
u
m
n
−
i
P_{n-sum}^{n-i}
Pn−sumn−i表示,因为那
s
u
m
sum
sum个必选的数都要放前面,所以
(
n
−
s
u
m
)
(n-sum)
(n−sum)个数可供选择放后面
(
n
−
i
)
(n-i)
(n−i)个位置,用排列
P
P
P
(
i
−
1
)
!
∗
s
u
m
(i-1)!*sum
(i−1)!∗sum表示,选定当前第i位,因为这个时候完成任务,所以这个位置一定是sum个数之一,所以有sum种选择,前面
(
i
−
1
)
(i-1)
(i−1)个位置随便排,
(
i
−
1
)
!
(i-1)!
(i−1)!种方案
最终的答案为
a
n
s
=
∑
i
=
s
u
m
n
i
∗
f
i
=
∑
i
=
s
u
m
n
(
n
−
s
u
m
)
!
∗
i
!
∗
s
u
m
(
i
−
s
u
m
)
!
=
s
u
m
∗
∑
i
=
s
u
m
n
(
n
−
s
u
m
)
!
∗
i
!
(
i
−
s
u
m
)
!
ans=\sum_{i=sum}^{n}i*f_i=\sum_{i=sum}^{n}\frac{(n-sum)!*i!*sum}{(i-sum)!}=sum*\sum_{i=sum}^{n}\frac{(n-sum)!*i!}{(i-sum)!}
ans=∑i=sumni∗fi=∑i=sumn(i−sum)!(n−sum)!∗i!∗sum=sum∗∑i=sumn(i−sum)!(n−sum)!∗i!
公式就这么出来啦
注意点:提高速度,令 p o w e r [ i ] = i ! , i n v [ i ] = 1 i ! 在 1 0 9 + 7 在 的 逆 元 power[i]=i!,inv[i]=\frac{1}{i!}在10^9+7在的逆元 power[i]=i!,inv[i]=i!1在109+7在的逆元
Code:
#include <bits/stdc++.h>
#define LL long long
#define qy 1000000007
#define maxn 10000010
using namespace std;
LL power[maxn], inv[maxn];
bool vis[maxn];
LL ksm(LL n, int k){
if (!k) return 1;
LL sum = ksm(n, k >> 1);
sum = sum * sum % qy;
if (k & 1) sum = sum * n % qy;
return sum;
}
int main(){
power[0] = 1;
LL l, r;
scanf("%lld%lld", &l, &r);
int n = r - l + 1;
for (int i = 1; i <= n; ++i) power[i] = power[i - 1] * i % qy;
inv[n] = ksm(power[n], qy - 2);
for (int i = n; i; --i) inv[i - 1] = inv[i] * i % qy;
if (l == 1) printf("%lld\n", power[n] * (n + 1) % qy * ksm(2, qy - 2) % qy); else{
LL ans = 0, sum = 0;
for (int i = l; i <= r; ++i)
if (!vis[i]){
++sum;
for (int j = i << 1; j <= r; j += i) vis[j] = 1;
}
for (int i = sum; i <= n; ++i) ans = (ans + power[n - sum] * power[i] % qy * inv[i - sum] % qy) % qy;
printf("%lld\n", sum * ans % qy);
}
return 0;
}

博客针对一道题目给出不同数据范围的解题方法。对于20%的n<=8情况采用暴力法;10%的l=1情况进行特判;100%情况推导公式,先特判l=1,用筛法预处理出特定数个数sum,再推导方案数公式,最后得出最终答案公式,还提及提高速度的注意点。
384

被折叠的 条评论
为什么被折叠?



