标签:
题目链接:HDU 5775
题面:
for(int i=1;i<=N;++i)
for(int j=N,t;j>i;—j)
if(P[j-1] > P[j])
t=P[j],P[j]=P[j-1],P[j-1]=t;
2 3 3 1 2 3 1 2 3
Case #1: 1 1 2 Case #2: 0 0 0HintIn first case, (3, 1, 2) -> (3, 1, 2) -> (1, 3, 2) -> (1, 2, 3) the leftmost place and rightmost place of 1 is 1 and 2, 2 is 2 and 3, 3 is 1 and 3 In second case, the array has already in increasing order. So the answer of every number is 0.
题意:
给定一个1-N的随机排列,对此序列进行冒泡排序,问在排序过程中,每个数到达过的最右端和最左端的差值。
解题:
因为排序的具体过程是从右侧开始,每次将当前最小的值移到最左端,故一个数会到达的最右位置是它的起始位置+其右侧小于它的数字数量(在后面比他小的数向左移动的过程中,它会向右移动这么多步)。最左位置是其原来位置和排序之后应该处于的位置,两者的小者。最后,两个位置作差即为所求。
关键点是在于如何统计一个数右侧有几个数比它小,可以从右往左遍历,用树状数组维护,因为是边移动边统计的,每次就可以直接询问【1-a[j]-1】的和,即为右侧小于a[j]的数字的数量。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define inf 1000000
using namespace std;
int a[100010],c[100010],ans[100010];
int t,n;
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
void update(int i,int val)
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
int main()
{
int tmp,le,ri;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d",&n);
for(int j=0;j<n;j++)
scanf("%d",&a[j]);
memset(c,0,sizeof(c));
for(int j=n-1;j>=0;j--)
{
tmp=sum(a[j]);
update(a[j],1);
le=min(a[j]-1,j);
ri=j+tmp;
ans[a[j]]=ri-le;
}
printf("Case #%d:",i);
for(int j=1;j<=n;j++)
printf(" %d",ans[j]);
printf("\n");
}
return 0;
}标签:
原文地址:http://blog.csdn.net/david_jett/article/details/52072727