6318.Swaps and Inversions

这个题就是找逆序对,然后逆序对数*min(x,y)就可以了。

官方题解:注意到逆序对=交换相邻需要交换的次数,那么输出 逆序对个数 即可。

求逆序对有4种操作,线段树 、BIT、归并排序、树状数组。

我敲了线段树、归并排序和树状数组版的。

关于这几种方法求逆序对,自行百度吧,懒了。。。

代码(线段树版-注意排序):

 //1010-找逆序对数-线段树求逆序对数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const double eps=1e-;
const int maxn=1e5+;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<]; void PushUp(int rt)
{
sum[rt]=sum[rt<<]+sum[rt<<|];
} void build(int l,int r,int rt)
{
sum[rt]=;
if(l==r){
return ;
} int m=(l+r)>>;
build(lson);
build(rson);
PushUp(rt);
} void update(int p,int l,int r,int rt)
{
if(l==r){
sum[rt]++;
return ;
} int m=(l+r)>>;
if(p<=m)update(p,lson);
else update(p,rson);
PushUp(rt);
} ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
return sum[rt];
}
int m=(l+r)>>;
ll ret=;
if(L<=m) ret+=query(L,R,lson);
if(R> m) ret+=query(L,R,rson);
return ret;
} int a[maxn],b[maxn];
int main()
{
int n,x,y;
while(~scanf("%d%d%d",&n,&x,&y)){
build(,n,);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,b+n+);
int len=unique(b+,b+n+)-b-;
for(int i=;i<=n;i++){
a[i]=upper_bound(b+,b+len+,a[i])-b-;
} ll sum=;
for(int i=;i<=n;i++){
sum+=query(a[i]+,n,,n,);
update(a[i],,n,);
}
printf("%lld\n",sum*min(x,y));
}
return ;
}

代码(归并排序版):

 //1010-6318-求逆序对数-归并排序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cassert>
using namespace std;
typedef long long ll;
const int maxn=1e5+;
const int inf=0x3f3f3f3f; int a[maxn],tmp[maxn];
ll ans; void Merge(int l,int m,int r)
{
int i=l;
int j=m+;
int k=l;
while(i<=m&&j<=r){
if(a[i]>a[j]){
tmp[k++]=a[j++];
ans+=m-i+;
}
else{
tmp[k++]=a[i++];
}
}
while(i<=m) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(int i=l;i<=r;i++)
a[i]=tmp[i];
} void Merge_sort(int l,int r)
{
if(l<r){
int m=(l+r)>>;
Merge_sort(l,m);
Merge_sort(m+,r);
Merge(l,m,r);
}
} int main()
{
int n,x,y;
while(~scanf("%d%d%d",&n,&x,&y)){
memset(a,,sizeof(a));
memset(tmp,,sizeof(tmp));
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
ans=;
Merge_sort(,n);
printf("%lld\n",ans*min(x,y));
}
}

可以去看一下ACdreamer的博客。

代码(离散化+树状数组):

 //1010-6318-求逆序对-离散化+树状数组版
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<cassert>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=1e5+; int tree[maxn];
int n; int lowbit(int x)
{
return x&(-x);
} void update(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i)){
tree[i]+=val;
}
} ll getsum(int x)
{
ll ans=;
for(int i=x;i>;i-=lowbit(i)){
ans+=tree[i];
}
return ans;
} int a[maxn],b[maxn];
map<int,int> mp; int main()
{
int x,y;
while(~scanf("%d%d%d",&n,&x,&y)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,b++n);
int num=;
mp.clear();
for(int i=;i<=n;i++)
mp[b[i]]=num++;
for(int i=;i<=n;i++)
a[i]=mp[a[i]];
memset(tree,,sizeof(tree));
ll ans=;
for(int i=n;i>;i--){
ans+=getsum(a[i]-);
update(a[i],);
}
printf("%lld\n",ans*min(x,y));
}
return ;
}

就这样吧,溜了。

啊啊啊啊,cf又掉分了༼༎ຶᴗ༎ຶ༽

HDU 6318.Swaps and Inversions-求逆序对-线段树 or 归并排序 or 离散化+树状数组 (2018 Multi-University Training Contest 2 1010)的更多相关文章

  1. HDU 6318 - Swaps and Inversions - [离散化+树状数组求逆序数][杭电2018多校赛2]

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=6318 Problem Description Long long ago, there was an ...

  2. hdu 6318 Swaps and Inversions (线段树求逆序对数)

    Swaps and Inversions Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

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

    Swaps and Inversions Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  4. HDU 6318 Swaps and Inversions(归并排序 || 树状数组)题解

    题意:一个逆序对罚钱x元,现在给你交换的机会,每交换任意相邻两个数花钱y,问你最少付多少钱 思路:最近在补之前还没过的题,发现了这道多校的题.显然,交换相邻两个数逆序对必然会变化+1或者-1,那我们肯 ...

  5. [HDU 6318] Swaps and Inversions

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6318 [算法] 线段树 / 树状数组 [代码] #include<bits/stdc++.h ...

  6. 【a703】求逆序对(线段树的解法)

    Time Limit: 10 second Memory Limit: 2 MB 问题描述 给定一个序列a1,a2...an.如果存在i小于j 并且ai大于aj,那么我们称之为逆序对,求给定序列中逆序 ...

  7. 归并排序(归并排序求逆序对数)--16--归并排序--Leetcode面试题51.数组中的逆序对

    面试题51. 数组中的逆序对 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出 ...

  8. poj2299树状数组入门,求逆序对

    今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...

  9. codeforces 459D D. Pashmak and Parmida's problem(离散化+线段树或树状数组求逆序对)

    题目链接: D. Pashmak and Parmida's problem time limit per test 3 seconds memory limit per test 256 megab ...

随机推荐

  1. POJ——2449 Remmarguts' Date

    Description "Good man never makes girls wait or breaks an appointment!" said the mandarin ...

  2. [洛谷P2602][ZJOI2010]数字计数

    题目大意:求区间$[l,r]$中数字$0\sim9$出现个数 题解:数位$DP$ 卡点:无 C++ Code: #include <cstdio> #include <iostrea ...

  3. MFC Button控件自绘

    文章参考地址:  http://blog.csdn.net/yue7603835/article/details/6649458    VC下的界面着实难看 有时候我们不得不自己进行控件的绘制 以前 ...

  4. 【BZOJ 2756】[SCOI2012]奇怪的游戏 二分+最大流

    这道题提醒我,要有将棋盘黑白染色的意识,尤其是看到相邻格子这样的条件的时候,然后就是要用到与其有关的性质与特点以体现其作用,这道题就是用到了黑格子与白格子之间的关系进行的,其出发点是每次一定会给一个黑 ...

  5. nfs 和samba

    NFS,是Network File System的简写,即网络文件系统.网络文件系统是FreeBSD支持的文件系统中的一种,也被称为NFS. NFS允许一个系统在网络上与他人共享目录和文件.通过使用N ...

  6. 继承spring的validator接口,实现对数据的校验

    在org.springframework.validation这个包中提供了一些对数据校验的方法,其中Validator接口是其中的一个. 现在用Validator接口,完成对数据的校验. 第一步:先 ...

  7. es6+最佳入门实践(8)

    8.Promise 8.1.什么是异步? 要理解异步,首先,从同步代码开始说 alert(1) alert(2) 像上面的代码,执行顺序是从上到下,先后弹出1和2,这种代码叫做同步代码 alert(0 ...

  8. codevs1063 合并果子 优先队列(小根堆)

    题目传送门 这道题很容易想到优先把两堆重量最小的合并比较优 然后乱搞一下就可以啦 #include<cstdio> #include<cstring> #include< ...

  9. bzoj 1061 志愿者招募 费用流

    详见BYV的博客,写的非常全面https://www.byvoid.com/blog/noi-2008-employee /************************************** ...

  10. bzoj 1878 SDOI2009树状数组 离线操作

    本来想写2120的,结果想起来了这个 我们先对于询问左端点排序,用树状数组存区间字母个数,对于每种字母, 第一次出现的位置记录为1,剩下的记录为0,然后记录下,每种颜色 后面第一个和他相同颜色的位置 ...