BZOJ 4934: [Ceoi2016]kangaroo

DP题从来就是不会的。。。
对于波浪序列看成若干条链,s,t 不计入链中,最终序列就是 \(0\) 条链
\(f_{i,j}\) 为插入前 \(i\) 个数之后有 \(j\) 条链的情况
最后加入 \(n\) 只能合并 s,t 所在的链,而他们不在链中
所以答案就是 \(f_{n-1,0}\)
\(i\) 不是 s 或 t,那么可以新开一条链,或者合并之前的两条链,若 s 在之前处理过了,那么还存在一条链包括 s,但是没有计入 \(j\) 中,也可以和 \(j\) 条链合并,t 被处理过了也同理
\(i\) 是 s 或 t,那么可以新开一条链,但是不计入链中,或者和之前的 \(j\) 条链合并
可以借助笛卡尔树来理解,一个排列的笛卡尔树唯一确定
\(j\) 就可以看作当前有多少个连通块

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int cnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++cnt]=v;ne[cnt]=head[u];head[u]=cnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int cnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++cnt]=v;ne[cnt]=head[u];c[cnt]=w;head[u]=cnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) { if (x >= MOD) x -= MOD; if (x < 0) x += MOD; }

const int N = 2222;
int f[N][N];


int main() {
	int n, s, t;
	scanf("%d%d%d", &n, &s, &t);
	f[0][0] = 1;
	rep (i, 1, n) {
		rep (j, 0, n) if (f[i - 1][j]) {
			if (i != s && i != t) {
				M(f[i][j + 1] += f[i - 1][j]);
				if (j)
					M(f[i][j - 1] += 1LL * f[i - 1][j] * j % MOD * ((j - 1) + (i > s) + (i > t)) % MOD);
			} else {
				M(f[i][j] += f[i - 1][j]);
				if (j)
					M(f[i][j - 1] += 1LL * f[i - 1][j] * j % MOD);
			}
		}
	}
	printf("%d\n", f[n - 1][0]);
}
posted @ 2020-02-22 11:31  Mrzdtz220  阅读(132)  评论(0编辑  收藏  举报