题解:AT_agc067_d [AGC067D] Unique Matching
liuzhenhao09 · · 题解
大牛人题。给一个不一样的做法。
首先我们把这个问的东西反过来,也就是计算对于所有可能的排列,所对应的合法区间组的个数之和,容易发现排列不影响答案,所以可以默认
然后我们考虑一下合法区间组的条件,不难发现条件可以转化为:
-
l_i \leq i \leq r_i -
我们来尝试一下固定一下
也就是我们给
然后你发现有点卡住,因为这个区间取 max 没有什么很好的性质,我们考虑固定
然后你发现非常的顺利啊,你发现每个
我们先来推一下
那么
上界呢?我们想一下什么时候会有上界的影响,就是这个
看起来很完美了吧,我们有一个
接下来需要一些非人类观察了。我们发现
-
-
- $b_i-a_i+1$:如果 $i$ 是叶子,那么 $b_i-a_i+1=1$,否则 $b_i-a_i+1$ 为 $i$ 的最后一个儿子的子树大小。
完美的变成了一个树形结构,考虑类似区间
我们定义
定义
易知
写出
来看
答案为
#include<bits/stdc++.h>
#define int long long
using namespace std;
char buf[1<<21],*p1,*p2;
#define gc() getchar()
template <typename T>
inline void read(T& x){
x = 0;
int f = 1;
char ch = gc();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = gc();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + ch - '0';
ch = gc();
}
x *= f;
}
template <typename T>
inline void write(T x){
if(x < 0) putchar('-'),x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int INF = 1e18 + 7;
/*
struct edge{
int to,nxt;
}e[200010];
int nE = 0,hd[200010];
void add(int u,int v){
e[++nE] = (edge){v,hd[u]};
hd[u] = nE;
}
int fa[200010],cnt;
int Find(int i){
return fa[i] == i ? i : fa[i] = Find(fa[i]);
}
void Unite(int u,int v){
u = Find(u),v = Find(v);
if(u == v) return;
fa[u] = v;
cnt--;
}
int bit[200010];
int LSB(int i){
return i & (-i);
}
void upd(int i,int v){
while(i <= n){
bit[i] += v;
i += LSB(i);
}
}
int psq(int i){
int res = 0;
while(i){
res += bit[i];
i -= LSB(i);
}
return res;
}
*/
int n,MOD;
int f[5010],g[5010];
signed main(){
read(n),read(MOD);
f[1] = g[0] = g[1] = 1;
for(int i = 2; i <= n; i++){
for(int s = 1; s < i; s++) (f[i] += g[i - 1 - s] * f[s] % MOD * (i - s) % MOD * s) %= MOD;
for(int s = 1; s <= i; s++) (g[i] += g[i - s] * f[s] % MOD * (i - s + 1)) %= MOD;
}
for(int i = 1; i <= n; i++) (g[n] *= i) %= MOD;
printf("%lld",g[n]);
return 0;
}