题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5122
题意:告诉你一种排序方法是随机选择一个数,然后不停的向后交换,直到它后面的数不比它小,这样算一次。给出一个序列,问将其升序排好最少需要几次。
思路:我们每次将当前最大的数拿到最后面,这样是最优的。所以我们每次只需要判断第i个数需不需要移动,需要移动答案就加一。假设当前操作到了第k大的数,那么k就是最大的,比k大的数都拿到后面去排好序了,所以我们只需要看看原序列中比k小且位置在k之前的数是不是k-1个,就知道k需不需要移动了。用一个树状数组维护一下前缀和,将原序列扫一遍,对于数a[i],先把a[i]加到树状数组里,再查询一下[1,a[i]-1]区间内的个数是否为a[i]-1个来更新答案。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007
const int maxn = 1000001;
int sum[maxn+10];
int a[maxn+10];
int T,n;
int lowbit(int x)
{
return x&(-x);
}
void add(int x)
{
while( x <= maxn )
{
sum[x]++;
x+=lowbit(x);
}
}
int query(int x)
{
int ans = 0;
while( x > 0 )
{
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
void init()
{
scanf("%d",&n);
Clean(sum,0);
rep(i,1,n)
{
scanf("%d",&a[i]);
}
}
int solve()
{
int ans = 0;
rep(i,1,n)
{
add( a[i] );
if ( query( a[i] - 1 ) != a[i] - 1 ) ans++;
}
return ans;
}
int main()
{
cin>>T;
rep(kase,1,T)
{
init();
printf("Case #%d: %d\n",kase,solve());
}
return 0;
}