【题目】
题目描述:
给你一个长度为 n 的排列,小W每次可以选择一个数,做以下操作:
不断把这个数与它右边的数交换。
当它右边没有数,或它右边的数比它大时,停止操作。
比如序列 1 4 3 2 5,对 4 操作后就是 1 3 2 4 5 。
求最少需要进行几次操作,使得这个排列变成升序。输入格式:
第一行一个正整数 n 。
第二行 n 个数,从左到右描述给定的排列。
输出格式:
输出一个数表示答案。
样例数据:
输入:
5
3 2 5 1 4
输出:
3
备注:
样例说明:
按顺序选 5,2,3 。
数据规模与约定:
对于 30% 的数据,n≤100。
对于 50% 的数据,n≤1000。对于 100% 的数据,n≤1000000。
【分析】
乍一看呢,这道题似乎不是那么好做,而且数据范围也比较大,面对1e+6这么大的n,我们考虑用O(n logn)或者是O(n)的时间复杂度来解决
(反正我是不会告诉你我用暴力拿的50分)
首先,一个数只能往右边移动,那么当它的右边有比它小的数的时候,就必然会对它进行一遍操作
这样一来,问题就简单了,用一个数(假设为minn)记录这个数(假设为a[i])右边的数中最小的数,那么,当minn<a[i]时,答案就增加一,否则答案不变
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e+6+5;
const int oo=2e+9;
int a[N];
int main()
{
// freopen("sort.in","r",stdin);
// freopen("sort.out","w",stdout);
int n,i,s=0,minn=oo;
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
for(i=n;i>=1;--i)
{
if(minn<a[i])
s++;
minn=min(minn,a[i]);
}
printf("%d",s);
// fclose(stdin);
// fclose(stdout);
return 0;
}