【NOIP2004】合唱队形
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1091
水题。。。没啥好说的,求一遍正向的最长上升子序列和一遍逆向的最长上升子序列就可以了。
唯一需要注意的是,求最长上升子序列之类的那种O(n^2)算法中,定义dp[i]是指以第i个元素为结尾的最长上升子序列长度,而O(nlogn)算法中,是指考虑到第i个元素所能产生的最长上升子序列长度,如果要使用O(nlogn)的做法,需要维护以当前元素结尾的最长上升子序列。但是,,,这题的范围也太小了,我写的O(nlogn)的做法咋还没O(n^2)快呢!!!
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 105; 7 8 int h[maxn], dp[maxn], up[maxn]; 9 10 int main() { 11 int n, len = 0, ans = 0; 12 scanf("%d", &n); 13 for (int i = 1; i <= n; ++i) { 14 scanf("%d", &h[i]); 15 if (h[i] > dp[len]) dp[++len] = h[i], up[i] = len; 16 else { 17 int pos = lower_bound(dp + 1, dp + len + 1, h[i]) - dp; 18 dp[pos] = h[i], up[i] = pos; 19 } 20 } 21 len = 0; 22 for (int i = n; i >= 1; --i) { 23 int down = 0; 24 if (h[i] > dp[len]) dp[++len] = h[i], down = len; 25 else { 26 int pos = lower_bound(dp + 1, dp + len + 1, h[i]) - dp; 27 dp[pos] = h[i], down = pos; 28 } 29 if (ans < up[i] + down) ans = up[i] + down; 30 } 31 printf("%d", n - ans + 1); 32 return 0; 33 }