hdu 4911 Inversion(数论+线段树)

Inversion

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


Problem Description
bobo has a sequence a 1,a 2,…,a n. 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 a i>a j.
 

Input
The input consists of several tests. For each tests:

The first line contains 2 integers n,k (1≤n≤10 5,0≤k≤10 9). The second line contains n integers a 1,a 2,…,a n (0≤a i≤10 9).
 

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
 
若存在逆序数不为0,则当前这次交换一定能使的逆序数变小。
所以,只要统计初始逆序数大小是否大于k,若大于k,则减去k,否则为0.
统计逆序数用线段树。

#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;

const int maxn = 100020;
struct tree{
    int l , r , sum;
}a[4*maxn];
map<int , int> mp;
vector<int> num;
int n , K , cnt;

void build(int l , int r ,int k){
    a[k].l = l;
    a[k].r = r;
    a[k].sum = 0;
    if(l != r){
        int mid = (l+r)/2;
        build(l , mid , 2*k);
        build(mid+1 , r , 2*k+1);
    }
}

void add(int l , int r , int k ,int c){
    //cout << "a[k].l=" << a[k].l << " a[k].r=" << a[k].r << " l="<<l << "  r=" << r << endl;
    if(l <= a[k].l && a[k].r <= r){
        a[k].sum += c;
    }else{
        int mid = (a[k].l+a[k].r)/2;
        if(mid >= r) add(l , r , 2*k , c);
        else if(mid < l) add(l , r , 2*k+1 , c);
        else add(l  ,mid , 2*k , c) , add(mid+1 , r , 2*k+1 , c);
        a[k].sum = a[2*k].sum+a[2*k+1].sum;
    }
}

int querry(int l , int r , int k){
    //cout << "a[k].l=" << a[k].l << " a[k].r=" << a[k].r << " l="<<l << "  r=" << r << endl;
    if(l <= a[k].l && a[k].r <= r){
        return a[k].sum;
    }else{
        int mid = (a[k].l+a[k].r)/2;
        if(mid >= r) return querry(l , r , 2*k);
        else if(l > mid) return querry(l , r , 2*k+1);
        else return querry(l , mid , 2*k)+querry(mid+1 , r , 2*k+1);
    }
}

void initial(){
    mp.clear();
    num.clear();
    cnt = 1;
}

void readcase(){
    int tem;
    for(int i = 0; i < n; i++){
        scanf("%d" , &tem);
        num.push_back(tem);
        mp[tem] = 0;
    }
    for(map<int , int>::iterator it = mp.begin(); it != mp.end(); it++){
        it->second = cnt++;
    }
}

void computing(){
    build(0 , cnt , 1);
    long long int ans = 0;
    for(int i = 0; i < num.size(); i++){
        ans += querry(mp[num[i]]+1 , cnt , 1);
        add(mp[num[i]] , mp[num[i]] , 1 , 1);
    }
    //cout << "ans=" << ans << endl;
    if(ans < K) printf("0\n");
    else printf("%I64d\n" , ans-K);
}

int main(){
    while(~scanf("%d%d" ,&n , &K)){
        initial();
        readcase();
        computing();
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值