2014-multi-university-training-contest-5-Inversion (离散化加线段树)

Inversion

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1648    Accepted Submission(s): 458


Problem Description
  
  
bobo has a sequence a1,a2,…,an. He is allowed to swap two adjacent numbers for no more than k times. Find the minimum number of inversions after his swaps. Note: The number of inversions is the number of pair (i,j) where 1≤i<j≤n and ai>aj.
 

Input
  
  
The input consists of several tests. For each tests: The first line contains 2 integers n,k (1≤n≤105,0≤k≤109). The second line contains n integers a1,a2,…,an (0≤ai≤109).
 

Output
  
  
For each tests: A single integer denotes the minimum number of inversions.
 

Sample Input
  
  
3 1 2 2 1 3 0 2 2 1
 

Sample Output
  
  
1 2 做了那么多次的多校,终于打破一题的神话了,做了两题,哈哈,写下题解,也算激励激励自己。 这次的1001题很水,做法也很多,可以用归并,树状数组,线段树做,不过树状数组和线段树需要离 散化数据,数据太大了。 题意: 给你一组数据,和k次操作,每次操作可以交换任意两个相邻的数,问在不超出k次的操作下, 可以得到的最小逆序对; 做法: 仔细想一下就可以知道其实你每次移动减少的逆序对数都为一,所以可以先直接求出原来数组的 逆序对,再减去k即可; 代码如下:
/****************************************************** /
 /*                                                   /*
  *   ***********                                      *
  *           *      Auther:     ZSGG                  *
  *         *                                          *
  *       *          Name:     Inversion               *
  *     *                                              *
  *   ***********    Algorithm:   数据结构            *
  *                                                    *
  */
/*******************************************************/


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <queue>
#include <vector>
#include <cstdlib>
#include <algorithm>

#define ls u << 1
#define rs u << 1 | 1
#define lson l, mid, u << 1
#define rson mid + 1, r, u << 1 | 1

using namespace std;
typedef long long ll;
const int M = 1e5 + 5;
ll sum[M << 2];
int a[M],b[M];

void build_tree(int l, int r, int u)
{
    if(l == r)
    {
        sum[u] = 0;
    }
    else
    {
        int mid = (l + r) >> 1;
        build_tree(l, mid, ls);
        build_tree(mid + 1, r, rs);
        sum[u] = sum[ls] + sum[rs]; // 555555555这句话竟然忘记加了,太粗心了;
    }
}

void update(int pos, int l, int r, int u)
{
    if(l == r)
    {
        sum[u]++;
        return ;
    }

    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos, lson);
    else update(pos, rson);
    sum[u] = sum[ls] + sum[rs];
}

ll add(int L, int R, int l, int r, int u)
{
    if(L > R) return 0;
    if(L <= l && R >= r)
    {
        return sum[u];
    }
    ll res = 0;
    int mid = (l + r) >> 1;
    if(L <= mid) res += add(L, R, lson);
    if(R > mid)  res += add(L, R, rson);
    return res;
}

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);

    int n,k;
    while(~scanf("%d %d",&n,&k))
    {
        ll res = 0;
        for(int i = 0; i < n; i++) scanf("%d",a+i);
        copy(a, a + n, b);
        sort(b, b + n);
        int ans = unique(b, b + n) - b;//离散化
        build_tree(1, ans, 1);
        for(int i = 0; i < n; i++)
        {
            int ua = lower_bound(b, b + ans, a[i]) - b + 1;//二分查找数的位置
//            cout<<ua<<endl;
            res += add(ua + 1, ans, 1, ans, 1);//查找逆序对数
            update(ua, 1, ans, 1); //更新
        }
        res -= k;
        if(res <= 0) puts("0");
        else printf("%I64d\n",res);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值