初见安~这里是传送门:洛谷P4562 游戏
题目背景
九条可怜是一个富有的女孩子。
题目描述
她长大以后创业了,开了一个公司。 但是管理公司是一个很累人的活,员工们经常背着可怜偷懒,可怜需要时不时对办公室进行检查。
可怜公司有 nn 个办公室,办公室编号是 l到 l+n-1,可怜会事先制定一个顺序,按照这个顺序依次检查办公室。一开始的时候,所有办公室的员工都在偷懒,当她检查完编号是 ii 的办公室时候,这个办公室的员工会认真工作,并且这个办公室的员工通知所有办公室编号是 ii 的倍数的办公室,通知他们老板来了,让他们认真工作。因此,可怜检查完第 ii 个办公室的时候,所有编号是 ii 的倍数(包括 ii )的办公室的员工会认真工作。
可怜发现了员工们通风报信的行为,她发现,对于每种不同的顺序 pp ,都存在一个最小的 t(p),使得可怜按照这个顺序检查完前 t(p) 个办公室之后,所有的办公室都会开始认真工作。她把这个 t(p)定义为 p 的检查时间。
可怜想知道所有 t(p)t的和。
但是这个结果可能很大,她想知道和对 10^9+7109+7 取模后的结果。
输入格式
第一行输入两个整数 l,rl,r 表示编号范围,题目中的 nn 就是 r-l+1r−l+1 。
输出格式
一个整数,表示期望进行的轮数。
输入
2 4
输出
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 。
和是 1616 。
数据范围
对于 20% 的数据,
对于另 10% 的数据,
对于另 10% 的数据,
对于另 30% 的数据,
对于 100% 的数据,
题解
这个题的题意很奇怪啊……明明是求的所有情况耗时之和,也就是检查的数量之和,输出解释写的又成了轮数的期望了……不管,我们求的是和不是期望。
题意转化过来就是:问你在所有的检查顺序下,哪些房间是没有被前面的因数通报的。再换句话说,有些房间是关键的房间,不会被别的房间通报,也就是说没有数以它作为倍数,除了它自己。所以说你每次检查要花费的时间至少就是关键房间的数量,至多是所有房间的数量。
关键房间的数量很好求,假设有sum个,暴力筛就行了。接下来考虑答案怎么算——我们设表示恰好花费时间i检查完所有关键房间的情况数。那么就有:
再看怎么算。因为已经检查了i个房间了,也就是说还有
个房间没有检查,而这
个房间都不是关键房间,我们随便选
个不关键的再任意顺序即可,也就是有
种情况;再看选了的i种里面,因为只需要i的时间,所以第i次一定是选的关键房间中的一个,而前面的
次已经因为之前
个的组合数枚举固定了是哪
个房间,所以我们只考虑顺序,就有:
。所以:
。
公式已经有了,具体操作略。
上代码——
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 1e7 + 4;
const int p = 1e9 + 7;
typedef long long ll;
int read() {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
return x * f;
}
ll fac[maxn], inv[maxn], f[maxn], ans = 0;
ll C(ll n, ll m) {
if(!m) return 1;
return fac[n] * inv[m] % p * inv[n - m] % p;
}
ll power(ll a, ll b) {ll res = 1; while(b) {if(b & 1) res = (res * a) % p; a = a * a % p, b >>= 1;}return res;}
int l, r, n, sum = 0;
bool vis[maxn];
signed main() {
l = read(), r = read(); n = r - l + 1;
for(int i = l; i <= r; i++) if(!vis[i]) {
sum++;
for(int j = (i << 1); j <= r; j += i) vis[j] = true;//暴力筛
}
fac[1] = fac[0] = 1;
for(int i = 2; i <= n; i++) fac[i] = fac[i - 1] * i % p;//预处理阶乘
inv[n] = power(fac[n], p - 2); inv[0] = 1;//预处理逆元
for(int i = n - 1; i > 0; i--) inv[i] = inv[i + 1] * 1ll * (i + 1) % p;
for(int i = sum; i <= n; i++)
f[i] = C(n - sum, n - i) * fac[n - i] % p * sum % p * fac[i - 1] % p;
for(int i = sum; i <= n; i++) ans = (ans + i * f[i] % p) % p;
printf("%lld\n", ans);
return 0;
}
迎评:)
——End——