2020牛客暑期多校訓練營(第五場)D 思維|最長上升子序列

Drop Voicing

題目鏈接:https://ac.nowcoder.com/acm/contest/5670/D

題目描述:

給定一個n個數的序列,你可以對序列進行兩種操作

操作1:將當前序列的倒數第二個元素放置在序列首部,即a1,a2,a3,,,,aN變爲a1,an-1,a2,a3,,,aN

操作2:將當前序列的首部元素放置在序列尾部:即a1,a2,a3,,,aN變爲a2,a3,,,aN,a1

操作2不限次數,不算操作,連續的多次進行操作1被視爲一次操作,問最少需要多少次操作可以將序列轉換爲上升序列

思路:

可以把這個序列看成一個環,操作2可以理解成轉動這個環,對當前序列元素的相對位置並無影響,由操作2我們可以得到該序列的n種排列,然後對於每種排列我們求它的LIS(最長上升子序列),當前序列的LIS代表了這個序列不需要改動位置的元素,剩下的每個元素的位置改動需要經過數次操作1後即可達到目的。所以結果就是序列長度減去所有排列種最大的LIS。

多次操作1的實質是:可以將一個數轉移到任意一個位置

代碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6;
const double PI = acos(-1.0);
#define Test ll tesnum;tesnum = read();while(tesnum--)
ll read();

int main()
{
    int n;
    vector<int> v;
    cin>>n;
    for(int i = 1; i <= n; i++){
        int x;
        cin>>x;
        v.push_back(x);
    }
    int ans  = 0;
    for(int i = 0; i < n; i++){
        vector<int> low,now;
        int cnt = 0,j = i;
        while(cnt<n)
        {
            now.push_back(v[j]);
            j++;
            if(j==n)j= 0;
            cnt++;
        }
        low.push_back(now[0]);
        for(j = 1; j < n; j++){
            if(now[j]>low[low.size()-1]){
                low.push_back(now[j]);
            }else{
                vector<int>::iterator ite = upper_bound(low.begin(),low.end(),now[j]);
                if(ite==low.end()){
                    low.push_back(now[j]);
                }else
                    *ite = now[j];
            }
        }
        int res = low.size();
        ans = max(ans,res);
    }
    cout<<n-ans<<endl;
    return "BT7274", NULL;
}

inline ll read() {
    ll hcy = 0, dia = 1;char boluo = getchar();
    while (!isdigit(boluo)) {if (boluo == '-')dia = -1;boluo = getchar();}
    while (isdigit(boluo)) {hcy = hcy * 10 + boluo - '0';boluo = getchar();}
    return hcy * dia;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章