HDU

来源:互联网 发布:福州天趣网络 编辑:程序博客网 时间:2024/06/05 04:50

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911

题目大意:最多移动相邻的数k次,求移动之后最小的逆序数

解题思路:对于一个已知的序列,因为是求最小的逆序数,所以我们一定是去移动相邻逆序的数对,现只考虑这两个数,假设只移动这两个数,这两个数后面的和前面的所有数的逆序数不发生变化,而对于这两个数小的那个,他的逆序数减一,大的逆序数不变,所以k次就可以减小k个逆序数,但最小逆序数为0。
对于求逆序数,一开始想到了树状数组,但因为数据范围过大,采用离散化的方法,把数字的大小映射成排名,详见代码。

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int MAXN = 100000 + 5;struct Node{    int _val, _pos;    Node(int val = 0, int pos = 0) :_val(val), _pos(pos){}    bool operator<(const Node& a)const    {        return _val < a._val;    }}node[MAXN];LL in[MAXN];int n, gt[MAXN];inline int lowbit(int x){    return x&(-x);}void add(int pos, int num){    while (pos <= n)    {        in[pos] += num;        pos += lowbit(pos);    }}LL sum(int end){    LL sum = 0;    while (end > 0)    {        sum += in[end];        end -= lowbit(end);    }    return sum;}int main(){    for (int k;scanf("%d%d", &n, &k) == 2;)    {        memset(in, 0, sizeof(in));        for (int i = 0;i < n;++i)        {            scanf("%d", &node[i]._val);            node[i]._pos = i+1;        }        sort(node, node + n);        int ranking = 1,pre;        for (int i = 0;i < n;++i)        {            if (i!=0&&node[i]._val != node[i - 1]._val)                    ranking++;            gt[node[i]._pos] = ranking;        }        LL ans = 0;        for (int i = 1;i <= n;++i)        {            add(gt[i], 1);            ans += i - sum(gt[i]);        }        printf("%I64d\n", (ans - k <= 0 ? 0LL : ans - k));    }    return 0;}
原创粉丝点击