1. 程式人生 > 其它 >[NOIP2004 提高組] 合唱隊形

[NOIP2004 提高組] 合唱隊形

[NOIP2004 提高組] 合唱隊形

難度:普及/提高-

題目連結:https://www.luogu.com.cn/problem/P1091

解題思路

這題與最長上升子序列相似

但是題意要求的數列為一個類似山峰的佇列

接下來我們仔細分析題目

t1< t2<t3 < ... <​ ti>ti+1> ti+2 > ...>tk

發現了什麼​

題意要求的數列可以拆分成一個最長上升子序列和一個最長下降子序列

那麼只要列舉峰頂所在的位置就行了

最長上升子序列

最長上升子序列可以用二分或動規求

二分:O(nlog2n)

動規:O(n^2)

可以看出二分更快

但是題目列舉需要求出所有項到第一項的最長上升子序列

二分需要一一計算

而動規不需要

所以這道題使用動規更快

二分:O(n^2log2n)

動規:O(n^2)

此處提供動規最長上升子序列的模板

#include<bits/stdc++.h>
using namespace std;
int n,a[1002],f[1002];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        f[i]=1;   //以第i個數為末尾的上升序列最初長度為1
    }
    for(int i=1;i<=n;i++)    //
列舉i的位置 for(int j=1;j<i;j++) //在i的前面找j的位置 if(a[i]>a[j]) //如果滿足條件,則第i個數可以放在j後邊 f[i]=max(f[j]+1,f[i]); //取較大的一種再放 printf("%d",*max_element(f+1,f+n+1)); //從 F[1]到F[n] 找最大值 return 0; }

解題程式碼

#include<bits/stdc++.h>
using namespace std;

const int N = 105
; int n,a[N],f1[N],f2[N],ans; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); f1[i]=1; f2[i]=1; } for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(a[i]>a[j]) f1[i]=max(f1[j]+1,f1[i]); for(int i=n;i>=1;i--) for(int j=n;j>i;j--) if(a[i]>a[j]) f2[i]=max(f2[j]+1,f2[i]); for(int i=1;i<=n;i++){ ans=max(ans,f1[i]+f2[i]-1); } printf("%d",n-ans); return 0; }