[SDOI2010]地精部落

题目传送门

这道题是一道$DP$题,思维难度比较大。

题意:先定义波形数组:满足当$i$全为奇数或偶数时,$a[i]>a[i-1]$且$a[i]>a[i+1]$。

求$n$的全排列中有多少个符合波形数组。

想法是:如果第$i$个数是山峰,下一个肯定是山谷,也就是说要从剩下的且比第$i$个数小的数中挑到第$i+1$个数中。反之要挑大的数。

我们记录状态为$f[i][j][0/1]$,$i$为剩下$i$个数,$j$表示有$j-1$个数小于刚刚选择的数,当第$3$个下标为$0$时,表示这是山谷,为$1$则说明是山顶。

推理知道$f[i][j][0]$能影响$f[i-1][j..i][1]$,$f[i][j][1]$能影响$f[i-1][1..j-1][0]$。

初始化为$f[n][0][0]=f[n][n+1][1]=1$,其他为$0$。原因在于:刚开始所有数都可以作为第一个数为山峰或山谷,要么没有数比上一层大,要么所有数比上一层都大。

最后求$f[0][1][0]+f[0][1][1]$的值即可。

此时时间复杂度为$O(n^3)$,空间为$O(n^3)$。

但是过不了。。

考虑将转移方程变化下,把刷表改成填表,就发现$f[i][j][1]=\sum_{x=0}^jf[i+1][x][0]$,$f[i][j][0]=\sum_{x=j+2}^{i+2}f[i+1][x][1]$,然后又发现可以在填表的过程中顺便求下$\Sigma$,于是就优化到了$O(n^2)$。

而空间可以通过滚动数组优化掉一维。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline int read() {
14     int w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxn = 4200 + 10;
21 
22 int f[2][maxn][2], n, P, cur = 1;
23 
24 int main() {
25     n = read(), P = read();
26 
27     memset(f, 0, sizeof(f));
28 
29     f[cur][0][0] = f[cur][n+1][1] = 1;
30 
31     repd(i, n-1, 0) {
32         cur ^= 1;
33         rep(j, 0, i+2) f[cur][j][0] = f[cur][j][1] = 0;
34         int v = f[cur^1][0][0];
35         rep(j, 1, i+1) {
36             v = (v + f[cur^1][j][0]) % P;
37             f[cur][j][1] = (f[cur][j][1] + v) % P;
38         }
39         v = f[cur^1][i+2][1];
40         repd(j, i+1, 1) {
41             f[cur][j][0] = (f[cur][j][0] + v) % P;
42             v = (v + f[cur^1][j][1]) % P;
43         }
44     }
45 
46     printf("%d", (f[cur][1][0] + f[cur][1][1]) % P);
47 
48     return 0;
49 }

这道题还可以用数学统计下手推方程。

posted @ 2019-01-30 15:31  AC-Evil  阅读(180)  评论(0编辑  收藏  举报