题目大意:给一个混乱的序列,只有一种可执行的操作:把每个数字放到最前面,问最少经过几次可以把这个序列弄成不降序的序列。
做法1:不难想到最差情况是移动n次,因为移动哪个数字,和什么时候移动这个数字都是由自己决定,不用想得过分复杂。
详细过程:首先想到所有逆序了的数字都是要移动的,所谓逆序就是在这个数字之前有比他大的数字,一遍扫描可以把逆序了的数字抽出来(实际并没有抽出来),剩下的数字是原来就保持非降序的数字。设抽出来的逆序的数字有x个,只需要x次移动可以把它们接在前面并且非降序,但如果我们放一个值在最前面的时候可能会破坏前面的非降序序列 (就会产生新的需要移动到后面的数字),这个时候要先放最大的来找出哪些数字还需要移动到后面去,找出后再一并处理计数即可,复杂度o(n)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
long long t,n,m;
long long a[maxn];
int main() {
scanf("%lld",&t);
while(t--) {
scanf("%lld",&n);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
long long cur = a[1];
long long mx = 0;
for(int i = 1; i <= n; i++) {
if(a[i] < cur)
mx = max(mx,a[i]);
cur = max(cur,a[i]);
}
long long res = 0;
cur = mx;
for(int i = 1; i <= n; i++) {
if(a[i] < cur) res++;
cur = max(cur,a[i]);
}
printf("%lld\n",res);
}
return 0;
}
做法2:将数列进行排序,弄出数列的最终形态,然后倒序扫描。
一个例子:3 6 1 5 2 4 7。
它的最终形态是 1 2 3 4 5 6 7。
倒序扫描,第一个位置是7,那么在原序列扫到7之前的那些数字都需要移动,然后第二个数字是6,原序列在6 和 7 之间的数字都需要移动(假如6在7的后面,说明7前面的数字全部要移动,因为要先把6移过来)
总结:要注意到移动可以是任意顺序移动,这是使问题简单化的一个关键。