CF1558D Top-Notch Insertions
题目描述
点此看题
考虑对一个长度为
现给出
解法
这道题是真的难,但是我一个学弟随便切掉了。
考虑初始序列
还是用上面的例子,由排序序列可以得到限制
- 如果
a_{i-1}\leq a_i ,那么a_i 一定在a_{i-1} 后面,限制已经被排序序列考虑。 - 如果需要插入,那么
a_i<a_j 会产生一个额外的限制,并且类似地其他的\leq 都已经被考虑过了。
设排序序列
现在的问题就是求
总结
一开始我想根据题目的限制建拓扑图,但是这样会多出来很多无用的限制反而不好考虑,所以一定要去除无效限制,本题就是用考虑排序序列的方法去除了很多无效限制。
计数问题要找映射关系,如果有双射关系很可能有大用处。
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int M = 400005;
const int MOD = 998244353;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int T,n,m,fac[M],inv[M];
void init(int n)
{
fac[0]=inv[0]=inv[1]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
for(int i=2;i<=n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD;
}
int C(int n,int m)
{
if(n<m || m<0) return 0;
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
namespace treap
{
int rt,cnt,ch[M][2],val[M],hp[M],tg[M];
void clear()
{
for(int i=1;i<=cnt;i++)
ch[i][0]=ch[i][1]=val[i]=tg[i]=0;
rt=cnt=0;
}
struct node
{
int p[2];
node() {p[0]=p[1]=0;}
}emp;
void add(int x,int v)
{
if(!x) return ;
val[x]+=v;tg[x]+=v;
}
void down(int x)
{
if(!tg[x]) return ;
add(ch[x][0],tg[x]);
add(ch[x][1],tg[x]);
tg[x]=0;
}
node split(int x,int v)
{
if(!x) return emp;
int d=val[x]<=v;down(x);
node y=split(ch[x][d],v);
ch[x][d]=y.p[d^1];
y.p[d^1]=x;
return y;
}
int merge(int x,int y)
{
if(!x || !y) return x+y;
if(hp[x]<hp[y])
{
down(x);
ch[x][1]=merge(ch[x][1],y);
return x;
}
down(y);
ch[y][0]=merge(x,ch[y][0]);
return y;
}
int get(int x)//creat an element x
{
cnt++;val[cnt]=x;
hp[cnt]=rand();
return cnt;
}
int find(int x)//exist x?
{
node t=split(rt,x-1),w=split(t.p[1],x);
if(w.p[0]>0)//exist
{
add(w.p[0],1);add(w.p[1],1);
rt=merge(t.p[0],merge(w.p[0],w.p[1]));
return 0;
}
//if not,we need to insert
w.p[0]=merge(get(x),w.p[1]);
add(w.p[0],1);
rt=merge(t.p[0],w.p[0]);
return 1;
}
}
signed main()
{
T=read();init(4e5);
while(T--)
{
n=read();m=read();
treap::clear();int ans=0;
for(int i=1;i<=m;i++)
{
int a=read(),b=read();
if(treap::find(b)) ans++;
}
printf("%lld\n",C(2*n-ans-1,n));
}
}