「Solution」华一高ks10.5 T2 & P1970 花匠

\(Updated\space2020.10.31\):更正证明

思路和洛谷第一篇题解类似,但是第一篇题解是能够被hack的,hack数据:

1
1

题解输出2,答案1

这里给出更完善的写法。

首先,回顾一下求非降子序列的写法:

int a[MAXN], d[MAXN];
int dp() {
  d[1] = 1;
  int ans = 1;
  for (int i = 2; i <= n; i++) {
    for (int j = 1; j < i; j++)
      if (a[j] <= a[i]) {
        d[i] = max(d[i], d[j] + 1);
        ans = max(ans, d[i]);
      }
  }
  return ans;
}

\(O(n^2)\) From OI Wiki

考场上,我就是按照非降子序列的思路AC了这道题。

AC Code

#include<bits/stdc++.h>
using namespace std;
int h[100005], ans1, ans2, f1 = 1, f2 = -1, n;
int cmp(int a, int b){
	if(a > b) return 1;
	else if (a < b) return -1;
	else return 0;
}
int main(){
//	freopen("flower.in", "r", stdin);
//	freopen("flower.out", "w", stdout);
	cin >> n;
	for(int i = 0; i < n; i++) cin >> h[i];
	ans1 = ans2 = 1;
	for(int i = 1; i < n; i++){
		if(cmp(h[i], h[i-1]) == f1) ans1++, f1 *= -1;
		if(cmp(h[i], h[i-1]) == f2) ans2++, f2 *= -1;
	}
	cout << max(ans1, ans2);
	return 0;
}

解题方法

常规来讲,这个部分应该放在代码前面,但是对于这么一道题,我认为先看代码再看讲解会更好。

有两种不同情况,ans1考虑输入数据中满足条件\(A\)的最长序列,ans2则考虑条件\(B\),输出时比较两者最终结果取较大者即可。

cmp函数是为了方便做比较。

f1f2数组分别是ans1ans2flag,代表序列\(g\)的下一个元素相比与末尾元素应该更大还是更小。

读懂代码应该没有什么难度,那么接下来,我们注意到,非降子序列复杂度是\(O(n^2)\),而上面的代码虽然思路和非降子序列一样,但复杂度是线性的,那么,我们来证明以上算法的正确性。

首先,设原序列为\(A\),新序列为\(B\),并且此时,由\(A_{1...n}\)已经构成了\(B_{1...m}\)

\(B_{m-1}>B_{m}\)\(B_{m-1}<B_{m}\)这两种情况是等价的,那么只讨论前者。

现在,程序在等待第一个\(A_i>A_{i-1}\)的数,假设\(B_m>...>A_{n+1}>A_{n+2}>...>A_{k-1}\),而\(A_k>A_{k-1}\),那么现在,我们只需要将\(B_m\)更改为\(A_{k-1}\),因为我们一定可以保证\(A_{k-1} < B_m\),然后再把\(A_k\)作为\(B_{m+1}\)即可,序列长度+1​,\(Q.E.D.\)

大水题

posted @ 2020-10-05 14:42  Liuxizai  阅读(133)  评论(0编辑  收藏