您的位置:首页 > 其它

hdu 4911 Inversion (逆序数变换)

2014-08-06 09:34 435 查看
归并排序求逆序数模板,O(nlogn)的分治算法。

题意:

求k次选择任意两个相邻数交换后得到的数列的最小逆序数。

算法:

当逆序数大于0时,交换任意两个相邻的数交换后,逆序数减1。

这样才能得到最小逆序数。

故答案为max(0LL,inversion)。

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 100005

using namespace std;

int a[maxn],tar[maxn];
typedef long long ll;
ll res;

void solve(int *a,int l,int m,int r)
{
    int l1=l,l2=m+1,c=0;
    while(l1<=m && l2<=r)
    {
        if(a[l1]<=a[l2])
            tar[c++] = a[l1++];
        else
        {
            tar[c++] = a[l2++];
            res += m-l1+1;
        }
    }
    while(l1<=m)
        tar[c++] = a[l1++];
    while(l2<=r)
        tar[c++] = a[l2++];
    for(int i=l,j=0;i<=r;i++,j++)
        a[i] = tar[j];
}

void merge_sort(int *a,int l,int r)
{
    if(l>=r) return ;
    int mid = (l+r)>>1;
    merge_sort(a,l,mid);
    merge_sort(a,mid+1,r);
    solve(a,l,mid,r);
}
ll max(ll a,ll b)
{
    return a>=b?a:b;
}

int main()
{
    int n,k;
    ll ans;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        res = 0;
        merge_sort(a,0,n-1);
        ans = max(res-k,0LL);
        printf("%I64d\n",ans);
    }
    return 0;
}


========================华丽的分界线==================

用树状数组求逆序数模板

原理:把数列按数从大到小排序,如果有相同大小的数,则按位置从大到小排序。

然后从大数开始插入(它读入时对应的位置),每次插入前统计该位置之前数的个数。

因为是从大到小插入的,所以如果比它大且位置靠前的数与它就能构成一组逆序数。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 100010

using namespace std;

struct node
{
    int v,id;
}s[maxn];
int c[maxn],n;
typedef long long ll;
ll res;

bool cmp(node x,node y)
{
    return ((x.v>y.v) || ((x.v==y.v)&&(x.id>y.id)));
}
int Lowbit(int x)
{
    return x&(x^(x-1));
}
ll Getsum(int pos)
{
    ll ret = 0LL;
    while(pos>0)
    {
        ret+=c[pos];
        pos -= Lowbit(pos);
    }
    return ret;
}
ll update(int pos)
{
    while(pos<=n)
    {
        c[pos]++;
        pos+=Lowbit(pos);
    }
}

int main()
{
    int k,x;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(c,0,sizeof(c));
        res = 0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&s[i].v);
            s[i].id = i;
        }
        sort(s+1,s+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            res += Getsum(s[i].id);
            update(s[i].id);
        }
        printf("%I64d\n",max(res-k,0LL));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: