zoukankan      html  css  js  c++  java
  • HDU 1394 Minimum Inversion Number

    http://acm.hdu.edu.cn/showproblem.php?pid=1394

    题意:

    给出一串数,每次把第一个数放到最后,求最小逆序数。

    思路:

    线段树。

    每个结点维护3个值,l,r,和num。l和r代表数值的范围,num代表在[l,r]这个范围内出现的数字个数(下标就代表了数值大小)。因为需要求逆序数,所以每新输入一个值,我们先找比它大的数,比如我们输入的值为a,那么此时它的逆序数肯定为[a+1,n]范围内出现的数字个数,然后我们就可以利用线段树自顶而下寻找。最后把这个新增的数添加进线段树里。

    计算出一个逆序数之后,其余的逆序数也就好办了,因为每次都是移动第一个数,那么它减少的逆序数为a[i],新增的逆序数为n-1-a[i]

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 20000 + 5;
     7 
     8 int a[50005];
     9 int ans;
    10 int sum;
    11 
    12 struct node
    13 {
    14     int l, r;
    15     int num;
    16 }t[maxn];
    17 
    18 int n;
    19 
    20 void build(int L, int R, int k)
    21 {
    22     t[k].l = L;
    23     t[k].r = R;
    24     t[k].num = 0;
    25     if (L == R)  return;
    26     int mid = (L + R) / 2;
    27     build(L, mid, 2 * k);
    28     build(mid + 1, R, 2 * k + 1);
    29 }
    30 
    31 void update(int x,int k)
    32 {
    33     if (t[k].l == x && t[k].r == x)
    34     {
    35         t[k].num = 1;
    36         return;
    37     }
    38     int mid = (t[k].l+t[k].r) / 2;
    39     if (x <= mid)  update(x, 2 * k);
    40     else  update(x, 2 * k + 1);
    41     t[k].num = t[2 * k].num + t[2 * k + 1].num;
    42 }
    43 
    44 
    45 void query(int L, int R, int k)
    46 {
    47     if (L <= t[k].l && R >= t[k].r)
    48     {
    49         ans += t[k].num;
    50         return;
    51     }
    52     int mid = (t[k].l+t[k].r) / 2;
    53     if (R <= mid)   query(L, R, 2 * k);
    54     else if (L > mid)    query(L, R, 2 * k + 1);
    55     else
    56     {
    57         query(L, mid, 2 * k);
    58         query(mid+1, R, 2 * k + 1);
    59     }
    60 }
    61 
    62 int main()
    63 {
    64     //freopen("D:\txt.txt", "r", stdin);
    65     int x;
    66     while (scanf("%d", &n) != EOF)
    67     {
    68         build(1, n, 1);
    69 
    70         sum = 0;
    71         for (int i = 1; i <= n; i++)
    72         {
    73             ans = 0;
    74             scanf("%d", &a[i]);
    75             query(a[i] + 1, n, 1);   //统计出大于a[i]的有多少个
    76             sum += ans;              //累加逆序数
    77             update(a[i], 1);
    78         }
    79         ans = sum;
    80         for (int i = 1; i <= n; i++)
    81         {
    82             sum = sum + n - 2 * a[i] - 1;
    83             ans = min(sum, ans);
    84         }
    85         printf("%d
    ", ans);
    86     }
    87 }
  • 相关阅读:
    Android作业10/21
    Android作业10/07
    Android作业0930
    Android作业 0923
    第四周作业
    第七周
    第六周
    第四周作业
    3.10第二次
    jsp第一次作业
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/6550419.html
Copyright © 2011-2022 走看看