首页 > 代码库 > hdu 2838 求逆序对

hdu 2838 求逆序对

  1. /*****************************************************************************************************************
  2. 题意:给你N个排列不规则的数,任务是把它从小到大排好,每次只能交换相邻两个数,交换一次的代价为两数之和,求最小代价
  3. 注意 每次交换 都必须只能交换相邻的2个
  4. 思路:对于当前数X,我们如果知道前面比它大的数有多少,假设为K,那么有部分代价是确定的,那就是K*X;
  5. 然后还得加上比它大的那些数之和,这就是当数列到X为止,排好所需要的最小代价。
  6. **********************************************************************************************************************/
  7. #include<iostream>
  8. #include<cstring>
  9. using namespace std;
  10. const int maxn=100001;
  11. struct node
  12. {
  13. int cnt;
  14. __int64 sum;
  15. }tree[maxn];
  16. int n;
  17. int lowBit(int x)
  18. {
  19. return x&(-x);
  20. }
  21. void modify(int x,int y,int t)
  22. {
  23. while(x<=n)
  24. {
  25. tree[x].sum+=y;
  26. tree[x].cnt+=t; //tree[].cnt来保存是否出现过a
  27. x+=lowBit(x);
  28. }
  29. }
  30. __int64 query_cnt(int x) //比x小的数的个数
  31. {
  32. __int64 sum=0;
  33. while(x>0)
  34. {
  35. sum+=tree[x].cnt;
  36. x-=lowBit(x);
  37. }
  38. return sum;
  39. }
  40. __int64 query_sum(int x) //比x小的所有数之和
  41. {
  42. __int64 sum=0;
  43. while(x>0)
  44. {
  45. sum+=tree[x].sum;
  46. x-=lowBit(x);
  47. }
  48. return sum;
  49. }
  50. int main()
  51. {
  52. while(~scanf("%d",&n))
  53. {
  54. int a;
  55. __int64 ans=0;
  56. memset(tree,0,sizeof(tree));
  57. for(int i=1;i<=n;i++)
  58. {
  59. scanf("%d",&a);
  60. modify(a,a,1); //以a为下标更新数组
  61. __int64 k1=i-query_cnt(a); //k1为前i个数比a大的数的个数
  62. if(k1!=0)
  63. {
  64. __int64 k2=query_sum(n)-query_sum(a); //目前所有数的和-目前所有比a小的数的和,为比a大的数的和
  65. ans+=k1*a+k2; //调换a所需的时间
  66. }
  67. }
  68. printf("%I64d\n",ans);
  69. }
  70. system("pause");
  71. return 0;
  72. }



来自为知笔记(Wiz)


附件列表

     

    hdu 2838 求逆序对