【算法】DP||贪心
【题解】
(1)动态规划:
令f[i][0..1]为两种条件下前i株花的最大保留数量,状态转移方程:
f[i][0]=max(f[j][1]+1) (j=i-1...1)(h[i]>h[j])
f[i][1]=max(f[j][0]+1) (j=i-1...1)(h[i]<h[j])
初始化:f[i][0]=f[i][1]=1,这样时间复杂度是O(n^2)。
由于题目的数据范围中有一句话:所有的h_i随机生成,所有随机数服从某区间内的均匀分布。
所以加个优化,因为f[i][0](i=1...n)和f[i][1](i=1...n)存在单调性(不下降),即f[x][0]>=f[y][0](x>y),f[x][1]>=f[y][1](x>y)
所以在状态转移枚举j时,当f[i][0]和f[i][1]都>1(大于初始值)时,就可以不用再向前找j而是直接跳向下一个i。
优化后可以通过所有数据(AC)。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=100010; int f[maxn][2],h[maxn],n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&h[i]); f[i][0]=1;f[i][1]=1; } for(int i=2;i<=n;i++) for(int j=i-1;j>=1;j--) { if(h[i]>h[j])f[i][1]=max(f[i][1],f[j][0]+1); if(h[i]<h[j])f[i][0]=max(f[i][0],f[j][1]+1); if(f[i][0]>1&&f[i][1]>1)break;//剪枝优化,单调性 } printf("%d",max(f[n][0],f[n][1])); return 0; }
(2)贪心
学自:http://tieba.baidu.com/p/2714238975
先把序列中相邻的相同元素删剩一个(去重),然后在序列中寻找所有满足a[i-1]<a[i]>a[i+1]或者a[i-1]>a[i]<a[i+1]的元素,这样的元素个数即答案。
解释:去重后的序列就是在不断波动,因此这两种元素一定会交替出现,而相邻的这两种元素中间的一段,这一段必然是单调递增或者单调递减的,因此最多选择两个元素,而选择两个端点就必然是最优的。
这样时间复杂度是O(n)。
#include<cstdio> int a[100010],b[100010],n,ans,tot; int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); b[(tot=1)]=a[1]; for(int i=2;i<=n;i++) if(a[i]!=b[tot])b[++tot]=a[i]; ans=2;//1和n for(int i=2;i<tot;i++) if((b[i]<b[i-1]&&b[i]<b[i+1])||(b[i]>b[i-1]&&b[i]>b[i+1]))ans++; if(tot==1)ans=1;if(tot==0)ans=0; printf("%d",ans); return 0; }