题目链接:http://codeforces.com/contest/1558/problem/D
如果没有插入的条件限制,那么对于所有元素都有 (a[i] <= a[i+1])
每次插入相当于确定了一个小于关系,将 (x) 位置的元素插入到 (y) 位置,相当于 (a[x] < a[y])
所以假设我们已经知道有 (c) 个 ‘(<)’ 关系,设排列后的序列为 (b),则有 (c) 个位置满足 (b[i]<b[i+1]),有 (n-1-c) 个位置满足 (b[i]<=b[i+1])(其中每个位置是什么关系已知),求有多少种序列 (b)
答案为 (C_{2*n-1-c}^n),考虑对于 (n-1-c) 个满足相等关系的位置,将 (b[i+1],dots,b[n]) 这些元素全部 (+1),那么最大可能的元素为 (n+n-1-c),也即这一序列与在 (2*n-1-c) 的排列中选出 (n) 个数构成了双射
如果将插入操作顺序反过来,逆向操作,那么每次插入的位置 (y) 的意义就是当前所有未填位置中第 (y) 大的位置 (p)(初始未填位置为 (1) 到 (n)),而若当前第 (y+1) 大位置为 (q),那么 (p<q),如果没有其他元素 (w) 与 (q) 满足 (w<q),则 (c++),否则 (c) 不变,(w) 与 (p) 满足 (w<=p),找到未被选择的第 (k) 个位置可以使用线段树
题目中说明不保证所有数据中 (n) 的和的范围,那么考虑到每次最多操作 (m) 次,记录操作的位置,最后将操作撤回即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200010;
const int M = 998244353;
int T, n, m, c;
int l[maxn], r[maxn], vis[maxn];
int fac[2*maxn], ifac[2*maxn];
struct Node{
int sum;
}t[maxn<<2];
void pushup(int i){
t[i].sum = t[i<<1].sum + t[i<<1|1].sum;
}
void build(int i, int l, int r){
if(l == r) {
t[i].sum = 1;
return;
}
int mid = (l + r) >> 1;
build(i<<1, l, mid); build(i<<1|1, mid + 1, r);
pushup(i);
}
void modify(int i, int p, int v, int l, int r){
if(l == r){
t[i].sum = v;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) modify(i<<1, p, v, l, mid);
else modify(i<<1|1, p, v, mid + 1, r);
pushup(i);
}
int query(int i, int k, int l, int r){
if(l == r){
return l;
}
int mid = (l + r) >> 1;
if(t[i<<1].sum >= k) return query(i<<1, k, l, mid);
else return query(i<<1|1, k-t[i<<1].sum, mid + 1, r);
}
int qsm(int i, int po){
int res = 1;
while(po){
if(po & 1) res = 1ll * res * i % M;
po >>= 1;
i = 1ll * i * i % M;
}
return res;
}
vector<int> vp;
vector<int> vq;
int C(int x, int y){
return 1ll * fac[x] * ifac[y] % M * ifac[x-y] % M;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
T = read();
fac[0] = 1;
for(int i = 1 ; i <= 400000 ; ++i) fac[i] = 1ll * fac[i-1] * i % M;
ifac[400000] = qsm(fac[400000], M - 2);
for(int i = 399999 ; i >= 0 ; --i) ifac[i] = 1ll * ifac[i+1] * (i+1) % M;
build(1, 1, 200000);
while(T--){
vp.clear(); vq.clear();
c = 0;
n = read(), m = read();
for(int i = 1 ; i <= m ; ++i){
l[i] = read(), r[i] = read();
}
for(int i = m ; i >= 1 ; --i){
int p = query(1, r[i], 1, 200000);
int q = query(1, r[i]+1, 1, 200000);
vp.push_back(p);
vq.push_back(q);
modify(1, p, 0, 1, 200000);
if(!vis[q]) {
++c;
vis[q]++;
}
}
printf("%d
", C(2*n-c-1, n));
for(auto u : vp) modify(1, u, 1, 1, 200000);
for(auto u : vq) vis[u] = 0;
}
return 0;
}