HDU 6318 Swaps and Inversions 思路很巧妙!!!(转换为树状数组或者归并求解逆序数)

Swaps and Inversions

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2315    Accepted Submission(s): 882

Problem Description

Long long ago, there was an integer sequence a.
Tonyfang think this sequence is messy, so he will count the number of inversions in this sequence. Because he is angry, you will have to pay x yuan for every inversion in the sequence.
You don‘t want to pay too much, so you can try to play some tricks before he sees this sequence. You can pay y yuan to swap any two adjacent elements.
What is the minimum amount of money you need to spend?
The definition of inversion in this problem is pair (i,j) which 1≤i<j≤n and ai>aj.

Input

There are multiple test cases, please read till the end of input file.
For each test, in the first line, three integers, n,x,y, n represents the length of the sequence.
In the second line, n integers separated by spaces, representing the orginal sequence a.
1≤n,x,y≤100000, numbers in the sequence are in [−109,109]. There‘re 10 test cases.

Output

For every test case, a single integer representing minimum money to pay.

Sample Input

3 233 666
1 2 3
3 1 666
3 2 1

Sample Output

0
3

Source

2018 Multi-University Training Contest 2

题目意思:
给你一个长度为n的数列
开始检查,如果某两个数不是从小大大顺序的,有一个就罚x元,
或者也可以直接在检查之前对不符合要求的调换位置(相邻的)
花费y元
然后要你求最小的花费
所以就是直接求这个序列的逆序数然后乘以x和y花费中较小的一个
逆序数可以归并或者数状数组求解

方法1归并:

#include<stdio.h>
#include<memory>
#include<algorithm>
#define max_v 100005
using namespace std;
typedef long long LL;
LL a[max_v];
LL temp[max_v];
LL ans;
void mer(int s,int m,int t)
{
    int i=s;
    int j=m+1;
    int k=s;
    while(i<=m&&j<=t)
    {
        if(a[i]<=a[j])
        {
            temp[k++]=a[i++];
        }else
        {
            ans+=j-k;//求逆序数
            temp[k++]=a[j++];
        }
    }
    while(i<=m)
    {
        temp[k++]=a[i++];
    }
    while(j<=t)
    {
        temp[k++]=a[j++];
    }
}
void cop(int s,int t)
{
    for(int i=s;i<=t;i++)
        a[i]=temp[i];
}
void megsort(int s,int t)
{
    if(s<t)
    {
        int m=(s+t)/2;
        megsort(s,m);
        megsort(m+1,t);
        mer(s,m,t);
        cop(s,t);
    }
}
int main()
{
    int n;
    LL c1,c2;
    while(~scanf("%d %lld %lld",&n,&c1,&c2))
    {
        if(n==0)
            break;
        ans=0;
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);
        megsort(0,n-1);
        printf("%lld\n",ans*min(c1,c2));
    }
    return 0;
}
/*
题目意思:
给你一个长度为n的数列
开始检查,如果某两个数不是从小大大顺序的,有一个就罚x元,
或者也可以直接在检查之前对不符合要求的调换位置(相邻的)
花费y元
然后要你求最小的花费
所以就是直接求这个序列的逆序数然后乘以x和y花费中较小的一个
逆序数可以归并或者数状数组求解
*/

方法二:

直接树状树组加离散化

离散化其实就是数据范围压缩!!!,注意理解

#include<queue>
#include<set>
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define max_v 500005
int n;
struct node
{
    int v;
    int pos;
} p[max_v];
int c[max_v];
int re[max_v];
int maxx;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int d)
{
    while(x<max_v)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int getsum(int x)//返回1到x中小与等于x的数量
{
    int res=0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
bool cmp(node a,node b)
{
   if(a.v!=b.v)
     return a.v<b.v;
   else
    return a.pos<b.pos;
}
int main()
{
    long long c1,c2;
    while(~scanf("%d %lld %lld",&n,&c1,&c2))
    {
        if(n==0)
            break;
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i].v);
            p[i].pos=i;
        }

        sort(p+1,p+1+n,cmp);

        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            ans+=(i-getsum(p[i].pos)-1);//先找再更新,避免getsum的时候算上自己
            update(p[i].pos,1);
        }
        printf("%lld\n",ans*min(c1,c2));
    }
    return 0;
}
[ Copy to Clipboard ]    [ Save to File]

原文地址:https://www.cnblogs.com/yinbiao/p/9471010.html

时间: 2024-08-28 19:53:31

HDU 6318 Swaps and Inversions 思路很巧妙!!!(转换为树状数组或者归并求解逆序数)的相关文章

HDU 6203 ping ping ping(dfs序+LCA+树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连通.问无法通行的点最少有多少个. 思路: 贪心思维,破坏两个点的LCA是最佳的.那么怎么判断现在在(u,v)之间的路径上有没有被破坏的点呢,如果没有的话那么此时就要破坏这个lca点.一开始我们要把询问按照u和v的lca深度从大到小排序,如果某个点需要被破坏,那么它的所有子节点都可以不再需要破坏别的点

HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gcd种类不超过loga[i]种). 预处理gcd如下代码,感觉真的有点巧妙... 1 for(int i = 1; i <= n; ++i) { 2 int x = a[i], y = i; 3 for(int j = 0; j < ans[i - 1].size(); ++j) { 4 int g

HDU 5156 - Harry and Christmas tree (dfs序+离线树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=5156 BC#25的C题. 题意是:给出一颗大小为n的树,以1为根,然后给出m次染色,每次将节点u加上一种颜色(一个节点可以有多个颜色). 最后查询树上每个节点对应子树上包含的不同颜色数量. 当时这场比赛没有做,回来看一下题目,没看标解就试着敲了一遍,于是解题思路从一开始就走上了不归路. 标解是O(n+m)的方法,主要思路是将问题转为:一次染色表示将u到根节点的路径都染上这种颜色. 但这样做需要去重,因为如果u

【HDU】4918 Query on the subtree 点分治+树状数组

传送门:[HDU]4918 Query on the subtree 题目分析: 首先,简化问题. 1.求一次到点u的距离不超过d的点的个数.很容易,一次O(NlogN)的点分治便可以完成. 2.多次进行操作1.此时不能每次都O(NlogN)了,太慢了.我们考虑到对于点分治,树的重心一共有logN层,第一层为整棵树的重心,第二层为第一层重心的子树的重心,以此类推,每次至少分成两个大小差不多的子树,所以一共有logN层.而且,对于一个点,他最多只属于logN个子树,也就是最多只属于logN个重心.

HDU 5465 Clarke and puzzle Nim游戏+二维树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5465 Clarke and puzzle Accepts: 42 Submissions: 269 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 克拉克是一名人格分裂患者.某一天,有两个克拉克(aa和bb)在玩一个方格游戏. 这个方格是一个n*mn∗m的矩阵,每个格子里有一

hdu 1166 敌兵布阵——(区间和)树状数组

here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T,表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50). 接下来每行有一条命令,命令有4种形式: (1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30) (2)Sub i j ,i和j为正整数,表示第i

hdu 1166 敌兵布阵——(区间和)树状数组/线段树

here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地.接下来有N个正整数,第i个正整数ai代表第i个工兵营地里開始时有ai个人(1<=ai<=50). 接下来每行有一条命令.命令有4种形式: (1) Add i j,i和j为正整数,表示第i个营地添加j个人(j不超过30) (2)Sub i j ,i和j为正整数,表示第i

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

hdu 5773 The All-purpose Zero 最长上升子序列+树状数组

题目链接:hdu 5773 The All-purpose Zero 官方题解:0可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的. 因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量. 为了保证严格递增,我们可以将每个权值S[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的. 个人看法:对于显然把所以0放进去部分我解释一下: 如果0位于最长上升子序列两边,这两个零要加进去是显然的 如果有一个0夹于最长上升子序列之间,那么