[小清新] [dp] P5999 kangaroo
题意
求出满足如下条件的
- 起点为
s ,终点为t 。 - 对于每个元素
a_i ,都有a_i>{a_{i-1},a_{i+1}} 或a_i<{a_{i-1},a_{i+1}} 。思路
条件
2 很难满足,那么考虑围绕它来做:考虑从小到大插入元素,这样i 插入到任意位置都是可以的,至少目前时这样的。
然后发现对于任意排列,都能每次找到最大的元素然后以它为中心把排列拆为两部分,不妨逆着做:把序列当成若干个连通块,每个连通块内部满足条件,那么
于是定义
事实上,对于“插入型
仔细想想,对于任意插入操作,都能被转化为后两种操作,于是舍去即可。
但是存在特殊情况不可转化:在最左边的块的左侧和最右边的块的右侧,只需特殊处理下就好。对于此题而言,分别对应的是
有些细节,具体见代码。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ADD(a, b) (a) = ((a) + (b)) % mod
const int N = 2e3 + 5, mod = 1e9 + 7;
int n, s, t, f[N][N];
signed main(){
cin >> n >> s >> t;
f[0][0] = 1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= i; ++j)
if(i == s || i == t)
ADD(f[i][j], f[i - 1][j] + f[i - 1][j - 1]);
else
ADD(f[i][j], f[i - 1][j + 1] * j + f[i - 1][j - 1] * (j - (i > s) - (i > t)));
//注意有时头和尾不能放
cout << f[n][1];
return 0;
}