JXOI 2018 简要题解
Posted zjp-shadow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JXOI 2018 简要题解相关的知识,希望对你有一定的参考价值。
「JXOI2018」游戏
题意
可怜公司有 (n) 个办公室,办公室编号是 (lsim l+n-1) ,可怜会事先制定一个顺序,按照这个顺序依次检查办公室。一开始的时候,所有办公室的员工都在偷懒,当她检查完编号是 (i) 的办公室时候,这个办公室的员工会认真工作,并且这个办公室的员工通知所有办公室编号是 (i) 的倍数的办公室,通知他们老板来了,让他们认真工作。因此,可怜检查完第 (i) 个办公室的时候,所有编号是 (i) 的倍数(包括 (i) )的办公室的员工会认真工作。
她发现,对于每种不同的顺序 (p) ,都存在一个最小的 (t(p)) ,使得可怜按照这个顺序检查完前 (t(p)) 个办公室之后,所有的办公室都会开始认真工作。她把这个 (t(p)) 定义为 (p) 的检查时间。
可怜想知道所有 (t(p)) 的和对 (10^9+7) 取模后的结果。
(l, n le 10^7)
题解
比较舒服的签到题。
我们定义 ([l, r]) 中的神仙数 (p) ,当且仅当 (p) 除了 (p) 外的任意一个因子都不存在于 ([l, r]) 中。
这个显然我们可以用线性筛预处理,做到 (O(n)) 的复杂度。其实也可以通过埃筛做到 (O(n ln ln n)) 的复杂度。
假设 ([l, r]) 中的神仙数共有 (tot) 个,那么就意味着只要这 (tot) 个数全部遍历过就可以结束了,反之不能结束。
这是很好证明的,因为这些数不遍历的话,那么不存在别的数能把他们消掉。反之这些数遍历了,别的数都能通过这些数消掉。
那么枚举在第几个数便利完,那么贡献就很好计算了:
[
sum_{i= tot}^{n} {i - 1 choose tot - 1} imes (tot - 1)! imes (n - tot)! imes i
]
假设在 (i) 处结束,那么第 (i) 个必为神仙数,那么就是在前 (i - 1) 个位置填 (tot - 1) 的排列,然后其他数可以随意安排,注意不要漏乘此处的贡献是 (i) 。
然后线性预处理逆元就可以把复杂度做到 (O(n)) 了。
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar() ) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("2544.in", "r", stdin);
freopen ("2544.out", "w", stdout);
#endif
}
typedef long long ll;
const int N = 1e7 + 1e3, Mod = 1e9 + 7;
ll fpm(ll x, int power) {
ll res = 1;
for (; power; power >>= 1, (x *= x) %= Mod)
if (power & 1) (res *= x) %= Mod;
return res;
}
int l, r, n; ll fac[N], ifac[N];
inline int C(int n, int m) {
if (n < 0 || m < 0 || m > n) return 0;
return 1ll * fac[n] * ifac[m] % Mod * ifac[n - m] % Mod;
}
void Init(int maxn) {
fac[0] = ifac[0] = 1;
For (i, 1, maxn) fac[i] = 1ll * fac[i - 1] * i % Mod;
ifac[maxn] = fpm(fac[maxn], Mod - 2);
Fordown (i, maxn - 1, 1)
ifac[i] = 1ll * ifac[i + 1] * (i + 1) % Mod;
}
bitset<N> vis;
int main () {
File();
l = read(); r = read(); n = r - l + 1;
Init(1e7);
int tot = 0, ans = 0;
For (i, l, r) if (!vis[i]) {
++ tot; for (int j = i; j <= r; j += i) vis[j] = true;
}
For (i, tot, n)
(ans += 1ll * C(i - 1, tot - 1) * fac[tot] % Mod * fac[n - tot] % Mod * i % Mod) %= Mod;
cout << ans << endl;
return 0;
}
后面两题先咕着,似乎不好做。。。
以上是关于JXOI 2018 简要题解的主要内容,如果未能解决你的问题,请参考以下文章