NOIP2013 提高组 花匠 题解
原题链接:Link
题目描述
思路
70分DP
看了各路大佬的题解,才知道原来有贪心的方法。让我这个写线段树的深深感受到了自己的弱小。。。
一开始就觉得这是一道DP题。考虑了两种状态定义方式:
- \(dp[i][0]\) 表示以第 \(i\) 盆花为截止,最后两盆花呈上升趋势时的最长序列长度; \(dp[i][1]\) 表示以第 \(i\) 盆花为截止,最后两盆花呈下降趋势时的最长序列长度。
- \(dp[i][0]\) 表示在前 \(i\) 盆花中,最后两盆花呈上升趋势时的最长序列长度; \(dp[i][1]\) 表示前 \(i\) 盆花中,最后两盆花呈下降趋势时的最长序列长度。
很快想出来了第一种的状态转移方程:枚举 \(i\) 之前的每一盆花 \(j\) ,则:1
2if (a[i] > a[j]) dp[i][0] = max(dp[i][0], dp[j][1] + 1);
if (a[i] < a[j]) dp[i][1] = max(dp[i][1], dp[j][0] + 1);
这样就有70分。 实际上有80 但是我居然怎么都想不到第2种的转移方程,后来看来各位大佬的题解才知道的。附在下面:1
2
3
4if (a[i] > a[i - 1]) dp[i][0] = dp[i - 1][1] + 1;
else dp[i][0] = dp[i - 1][0];
if (a[i] < a[i - 1]) dp[i][1] = dp[i - 1][0] + 1;
else dp[i][1] = dp[i - 1][1];
这样就是 \(O(n)\) 的。但是本juruo想不到啊。。。
所以我换了一个方法:用线段树维护。
100分解法
看到原来的转移方程:1
2if (a[i] > a[j]) dp[i][0] = max(dp[i][0], dp[j][1] + 1);
if (a[i] < a[j]) dp[i][1] = max(dp[i][1], dp[j][0] + 1);
其中 if (a[i] > a[j])
和 if (a[i] < a[j])
告诉我们:\(dp[i][0]\) 是所有以 比 \(a[i]\) 更高的花盆 结尾的“1”类序列的长度的最大值+1; \(dp[i][1]\) 是所有以比 \(a[i]\) 更高的花盆 结尾的“1”类序列的长度的最大值+1。
可能说的不太清楚。我们想象有一个数组 \(b\) ,用 \(b[i]\) 表示以高度为 \(i\) 的花盆结尾的最长长度。那么当我们遇到一个高度为 \(h\) 的花盆时,他的最长长度一定是 \(b[h...maxh]\) 的最大值再加一。那为了维护这个区间最大值,写一个支持单点修改,区间查询的线段树就好了。当然, 因为有两种不同的模式,也需要两棵线段树。
AC代码
1 |
|
可能数据比较水,跑得飞快:Link