专栏文章
CF 2127F Hamed and AghaBalaSar
CF2127F题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minvh2bc
- 此快照首次捕获于
- 2025/12/02 09:01 3 个月前
- 此快照最后确认于
- 2025/12/02 09:01 3 个月前
首先考虑这个 是什么。
发现跳(仅限第一个操作)的时候形如 ,贡献就为 。
于是在抵消之后,如果 最终跳到了 ,那么贡献就是 。
发现跳(仅限第一个操作)的时候形如 ,贡献就为 。
于是在抵消之后,如果 最终跳到了 ,那么贡献就是 。
然后会发现在给定了 的情况下,最后跳到的 一定是离 最近的 的 ,然后若 就会从 继续跳下去。
于是可以写出 的表达式:。
接下来考虑计数。
观察到 的表达式与 ,也就是最大值有关,并且整个序列都受最大值的限制。
于是先尝试在外层枚举 。
于是先尝试在外层枚举 。
此时尝试分开计算两部分的贡献:
- 。
- 。
首先考虑第 部分, 因为是枚举的可以抛开不看。
那么这个时候就可以把 拆开转为对每个 计算,会发现有 种情况:
那么这个时候就可以把 拆开转为对每个 计算,会发现有 种情况:
- ,这是因为 的值是固定的,而其他的值不是。
- 。
对于第 种情况,发现此时就需要解决一个问题:
计算 代表长度为 ,值域为 ,和为 的序列数量。
计算 代表长度为 ,值域为 ,和为 的序列数量。
对此并没有什么好求的做法,于是只能考虑容斥 的数的数量,可以得到:
。
。
看似好像求解就需要 的复杂度,但是实际上只有 的 是有用的,所以复杂度是 。
那么正好 是从 到 的,总复杂度就是 ,看样子就很有道理。
那么正好 是从 到 的,总复杂度就是 ,看样子就很有道理。
第 种情况的方案数就为 。
然后来考虑第 种情况。
因为每个元素只关心是不是 ,所以能够发现 这 个位置的情况是同样的,那么就只需要求出一个下标的值再乘上 就可以了。
单个下标是好算的,相当于此时的限制是 ,那么方案数就为 。
因为每个元素只关心是不是 ,所以能够发现 这 个位置的情况是同样的,那么就只需要求出一个下标的值再乘上 就可以了。
单个下标是好算的,相当于此时的限制是 ,那么方案数就为 。
于是第 种情况的方案数就为 。
接下来来考虑第 部分。
一样的尝试分讨,分为以下 种情况:
- 。
- 。
- 。
对于第 种情况,如果要枚举 的值复杂度就爆掉了,于是尝试其他的做法。
考虑 种合法的 的方案,这 个元素的和都为 。
又因为这 个元素是平等的,所以期望下应当有 。
或者说,也可以考虑一个合法的 的方案,考虑把其所有排列(根据值相同定义排列相同),那么每个位置在所有排列中的对应值的和应当是相等的,对所有等价类分析,就可以得到这个结果。
于是对应的答案就为 。
考虑 种合法的 的方案,这 个元素的和都为 。
又因为这 个元素是平等的,所以期望下应当有 。
或者说,也可以考虑一个合法的 的方案,考虑把其所有排列(根据值相同定义排列相同),那么每个位置在所有排列中的对应值的和应当是相等的,对所有等价类分析,就可以得到这个结果。
于是对应的答案就为 。
对于第 种情况,依然是只考虑一个元素,最后乘上 。
对于一个元素,那就是要求 。
于是答案就是 。
对于一个元素,那就是要求 。
于是答案就是 。
对于第 种情况,那就是要求 。
于是答案是 。
于是答案是 。
最后的时间复杂度为 。
其实在 的时候应该判一下第 部分的第 情况的,因为会涉及到除 ,不过因为本身会乘上 所以其实随便乘上一个不对的数也没什么问题。
C#include <bits/stdc++.h>
using ll = long long;
constexpr ll mod = 1000000007;
constexpr int N = 4e5;
inline ll qpow(ll a, ll b) {
ll v = 1;
for (; b; b >>= 1, a = a * a % mod) {
if (b & 1) {
v = v * a % mod;
}
}
return v;
}
ll fac[N + 1], ifac[N + 1];
inline void init() {
for (int i = fac[0] = 1; i <= N; i++) {
fac[i] = fac[i - 1] * i % mod;
}
ifac[N] = qpow(fac[N], mod - 2);
for (int i = N; i >= 1; i--) {
ifac[i - 1] = ifac[i] * i % mod;
}
}
inline ll C(int n, int m) {
return n < m || m < 0 ? 0ll : (fac[n] * ifac[n - m] % mod * ifac[m] % mod);
}
inline ll f(int n, int m, int mx) {
if (m < 0) {
return 0;
}
if (n == 0) {
return m == 0;
}
ll ans = 0;
for (int i = 0; i * (mx + 1) <= m && i <= n; i++) {
ll res = C(n, i) * C(m - i * (mx + 1) + n - 1, n - 1) % mod;
ans = (ans + mod + (i & 1 ? -res : res)) % mod;
}
return ans;
}
inline void solve() {
int n, m;
scanf("%d%d", &n, &m);
ll inv1 = qpow(n - 1, mod - 2), inv2 = qpow(n - 2, mod - 2);
ll ans = 0;
for (int mx = 0; mx <= m; mx++) {
ll x1 = f(n - 1, m - mx, mx) * mx % mod;
ll x2 = f(n - 2, m - mx * 2, mx) * (n - 1) % mod * mx % mod;
ll y1 = f(n - 1, m - mx, mx) * (m - mx) % mod * inv1 % mod;
ll y2 = f(n - 2, m - mx * 2, mx) * (n - 2) % mod * (m - mx * 2) % mod * inv2 % mod;
ll y3 = f(n - 2, m - mx * 2, mx) * mx % mod;
ans = (ans + x1 + x2 - y1 - y2 - y3 + mod * 3) % mod;
}
printf("%lld\n", ans);
}
int main() {
init();
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...