CF1558D Top-Notch Insertions
https://www.luogu.com.cn/problem/CF1558D
VP到这题卡住,吃了个饭以为懂了,结果回来发现看错题。。
不过考场上也不一定想得出来
先假设每个数前面的那个符号是 < = <= <=,如果有一个数插到它前面,它前面的符号就会变成 < < <(感性理解一下)
然后假设最后有
c
c
c个
<
<
<,那么就有
n
−
1
−
c
n-1-c
n−1−c个
<
=
<=
<=
根据基础的组合数学知识,当有
<
=
<=
<=时可以转换成加上一个编号
<
+
?
<+?
<+?,这样值域就变成了
n
+
n
−
1
−
c
n+n-1-c
n+n−1−c
从中选值,就可以得到最终的答案为
(
2
n
−
1
−
c
n
)
\large \binom{2n-1-c}{n}
(n2n−1−c)
现在考虑如何计算c
不论什么时候最前面一段一定是单调的
一开始先全部加进去
考虑从后往前删除(插入反过来),假设操作为
(
p
,
q
)
(p, q)
(p,q)
只需找到剩下的当中第
q
q
q大的和第
q
+
1
q+1
q+1大的的,
p
p
p是插到了
q
q
q这个位置,所以
q
+
1
q+1
q+1前面的符号变成了
<
<
<
然后再
p
p
p删掉
用一颗权值线段树维护即可
注意数据范围限制,处理一下细节问题即可
code:
#include<bits/stdc++.h>
#define N 400050
#define mod 998244353
#define ll long long
using namespace std;
int qpow(ll x, int y) {
ll ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
int fac[N], ifac[N], size[N << 2], x[N], y[N], n, m, t, vis[N], sta[N];
void init(int n) {
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = 1ll * fac[i - 1] * i % mod;
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
}
int C(int x, int y) {
if(x < y) return 0;
return 1ll * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}
void build(int rt, int l, int r) {
size[rt] = r - l + 1;
if(l == r) return ;
int mid = (l + r) >> 1;
build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
}
void update(int rt) {
size[rt] = size[rt << 1] + size[rt << 1 | 1];
}
void add(int rt, int l, int r, int x, int o) {
if(l == r) {
size[rt] += o;
return ;
}
int mid = (l + r) >> 1;
if(x <= mid) add(rt << 1, l, mid, x, o);
else add(rt << 1 | 1, mid + 1, r, x, o);
update(rt);
}
int query(int rt, int l, int r, int k) {
if(l == r) return l;
int mid = (l + r) >> 1;
if(size[rt << 1] >= k) return query(rt << 1, l, mid, k);
else return query(rt << 1 | 1, mid + 1, r, k - size[rt << 1]);
}
set<int> S;
int main() {
int lim = 2e5;
init(N - 20); build(1, 1, lim);
scanf("%d", &t);
while(t --) {
scanf("%d%d", &n, &m);
int top = 0; S.clear();
for(int i = 1; i <= m; i ++) scanf("%d%d", &x[i], &y[i]);
for(int i = m; i >= 1; i --) {
int p = query(1, 1, lim, y[i]), q = query(1, 1, lim, y[i] + 1);
S.insert(q); add(1, 1, lim, p, -1);
sta[++ top] = p;
}
int ans = S.size();
for(int i = 1; i <= top; i ++) add(1, 1, lim, sta[i], 1);
printf("%d\n", C(2 * n - 1 - ans, n));
}
return 0;
}