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;
}