• HDU 1394 Minimum Inversion Number(线段树求逆序对)


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

    题意:给定一个长度为n的序列,每次操作可以把序列前面的m个数移到序列后面去

       求在每次操作下的序列最小的逆序对数。

    题解:

      我们可以考虑用线段树先求出初始序列的逆序对数。对于移动m个数等价于

    先移动m-1个数再移动1个数,那我们只要移动当前的ai就可以得出所有的结果。

    实际上,把一个数移到后面去对整体逆序对的影响是:本来在ai后面比ai小的数与

    ai构成的逆序对不复存在,有ai个(因为数组从0开始所以不是ai-1)然后在ai后面

    比ai大的数将会与它构成新的逆序对,有n-1-ai个,那么移动当前ai的结果就是n-1-ai-ai

    分析到这里,题目就做完了,下面是代码:

     1 #define bug(x,y) cout<<"i="<<x<<": "<<y<<endl
     2 #define IO std::ios::sync_with_stdio(0);
     3 #include <bits/stdc++.h>
     4 #define itor ::iterator
     5 using namespace  std;
     6 typedef long long ll;
     7 typedef pair<ll,ll>P;
     8 #define pb push_back
     9 #define se second
    10 #define fi first
    11 #define rs o*2+1
    12 #define ls o*2
    13 const int N=5e3+5;
    14 int n;
    15 int sumv[N*4],a[N];
    16 void build(int o,int l,int r){
    17     sumv[o]=0;
    18     if(l==r){
    19         return;
    20     }
    21     int m=(l+r)/2;
    22     build(ls,l,m);
    23     build(rs,m+1,r);
    24 }
    25 void up(int o,int l,int r,int p){
    26     if(l==r){
    27         sumv[o]=1;
    28         return;
    29     }
    30     int m=(l+r)/2;
    31     if(p<=m)up(ls,l,m,p);
    32     else up(rs,m+1,r,p);
    33     sumv[o]=sumv[ls]+sumv[rs];
    34 }
    35 int query(int o,int l,int r,int ql,int qr){
    36     if(l>=ql&&r<=qr){
    37         return sumv[o];
    38     }
    39     int m=(l+r)/2;
    40     int res=0;
    41     if(ql<=m)res+=query(ls,l,m,ql,qr);
    42     if(qr>m)res+=query(rs,m+1,r,ql,qr);
    43     return res;
    44 }
    45 int main(){
    46     while(~scanf("%d",&n)){
    47         build(1,0,n-1);
    48         ll ans=0;
    49         for(int i=1;i<=n;i++){
    50             scanf("%d",&a[i]);
    51             int res=query(1,0,n-1,a[i]+1,n-1);
    52             //bug(i,res);
    53             ans+=res;
    54             up(1,0,n-1,a[i]);
    55         }
    56         ll h=ans;
    57         for(int i=1;i<n;i++){
    58             h+=(n-1-a[i]-a[i]);
    59             ans=min(ans,h);
    60         }
    61         printf("%lld
    ",ans);
    62     }
    63 }
    64 /*
    65 5
    66 2 1 0 4 3
    67 */
  • 相关阅读:
    CrackMe17
    逆向按钮事件定位
    CrackMe20
    CrackMe14
    CrackMe09
    CrackMe08
    分布式事务seata
    SpringBoot自动注入原理初解与实现
    InnoDB事务日志(redo log 和 undo log)详解
    高频面试题:Spring 如何解决循环依赖?
  • 原文地址:https://www.cnblogs.com/ccsu-kid/p/10598705.html
Copyright © 2020-2023  润新知