您的位置:首页 > 其它

hdu 4911 Inversion 树状数组求逆序数对

2014-08-05 22:05 351 查看


Inversion

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 389 Accepted Submission(s): 159



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




Author

Xiaoxu Guo (ftiasch)



Source

2014 Multi-University Training Contest 5



思路:水题,求一下逆序数对,然后-k即可;小于0时答案为0.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
const int maxn = 100005;
//#define mod 1000000007
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int n,k;
int a[maxn];
int b[maxn];
ll C[maxn];
int lowbit(int x) //二进制表达式中最右边的1所对应的值
{
	return x & -x;
}
ll sum(int x) //sum(x)表示从下标为1开始到下标为x的值的和
{
	ll ret = 0;
	while(x > 0)
	{
		ret += C[x];
		x -= lowbit(x);
	}
	return ret;
}
void add(int x,int d) //下标为x的点 + d
{
	while(x < maxn)
	{
		C[x] += d;
		x += lowbit(x);
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	//	 freopen("out.txt","w",stdout);
#endif  
	while (~scanf("%d%d",&n,&k)) 
	{
		ini(C);
		rep(i,n)
		{
			scan(a[i]);
			b[i] = a[i];
		}
		sort(b,b+n);
		ll ans = 0;
		for(int i = n-1; i >= 0; i--)
		{
			int p = lower_bound(b,b+n,a[i]) - b;
			p ++; //因为下标从1开始,所以下标+1
			ans += sum(p - 1);
			add(p , 1);
		}
		ans -= k;
		if(ans <= 0) puts("0");
		else cout<<ans<<endl;
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: