题目链接: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