2020牛客暑期多校訓練營(第五場) D-Drop Voicing
阿新 • • 發佈:2020-07-26
連結
https://ac.nowcoder.com/acm/contest/5670/D
題意
給定1~n的排列,有兩種操作
1:將倒數第二個元素放到最前面
2:將第一個元素放到最後
連續第一種操作若干次稱為一段
要求將該排列變為1,2,3,...,n ,且段數儘可能少,輸出這個最小值
思路
既然若干次操作1看作一段,那我們不妨將若干次操作1當作一種操作,即選擇1~n-1的最右邊若干元素,將它們放到最左邊
或等價於選擇1~n-1的某一元素,將它放在最右邊
我們可以發現如果將序列放在環上操作,第二種操作就僅相當於改變數字的下標,不改變元素間的相對位置
所以我們可以將一段操作1等價於在1~n的序列中選擇任一元素,將它放在最右邊
那麼若干段操作1我們就可以等價於將任一元素放在任意位置
於是我們只需找到環上的LIS,將其他不在LIS上的元素放到他們應該在的位置上即可
程式碼
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define ms(a) memset(a, 0, sizeof(a)) #define repu(i, a, b) for (int i = a; i < b; i++) #define repd(i, a, b) for (int i = a; i > b; i--) using namespace std; typedef long long ll; typedef long double ld; const int M = int(1e5) + 5; const int mod = int(1e9) + 7; int a[1005]; int d[1005]; int lis(int s, int t) { ms(d); repu(i, s, t + 1) { d[i] = 1; repu(j, s, i) { if (a[j] < a[i]) { d[i] = max(d[i], d[j] + 1); } } } return d[t]; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; repu(i, 0, n) { cin >> a[i]; } repu(i, 0, n) { a[i + n] = a[i]; } int ans = -1; repu(i, 0, n + n) { ans = max(ans, lis(i, i + n - 1)); } cout << n - ans << endl; return 0; }