「杂烩」精灵魔法(P1908逆序对弱化版)

题面:

题目描述

\(Tristan\)解决了英灵殿的守卫安排后,便到达了静谧的精灵领地——\(Alfheim\) 。由于$ Midgard$ 处在$ Alfheim\(和冥界\) Hel$ 的中间,精灵族领地尚未受到冥界恶灵的侵入。族长$ Galanodel \(为了帮助米德加尔特抵御外敌,对邪恶亡灵军团使用了高等魔法,从而使得亡灵军团每个士兵的行进速度变得不一致,从而打乱冥王\)Hel$安排的最佳阵型。

由于这个军团离\(Midgard\)还很远,因此在抵达$ Midgard$ 之前,对于$ A,B$ 两个亡灵,若$A \(的初始位置在\) B\(后面且\)A \(的速度比 快,\)A \(就会冲到\)B \(的前面去。现在\)Galanodel$ 想知道,会有多少对亡灵之间出现反超现象?

输入格式

第一行一个整数$ n$,表示排成一队的邪恶亡灵军团有多少人。

第二行\(n\)个整数\(a[i]\),表示邪恶亡灵们在数轴上的初始坐标。数据保证这些坐标全部不同。亡灵军团向数轴正方向前进。

第三行\(n\)个整数 \(v[i]\),表示邪恶亡灵们的行进速度。

输出格式

一行一个正整数\(k\),表示「反超」的个数。

样例

样例输入

3

1 2 3

2 1 3

样例输出

1

数据范围与提示

$ n<= 100000$

所有数据的绝对值均不超过\(maxlongint\)。

解法一:朴素的暴力(50pts)

一看就让我们求排序后的逆序对,\(O(n^2)\)搞它

代码:



/*#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
name=$GEDIT_CURRENT_DOCUMENT_NAME
pre=${name%.*}
g++ -O2 $dir/$name -o $pre -g -Wall -std=c++11
if test $? -eq 0; then
gnome-terminal -x bash -c "time $dir/$pre;echo;read;"
fi*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
typedef long long ll;
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n;
ll ans,minn,maxx;
struct Node{
ll d,v;
}a[maxn];
bool cmp(Node A,Node B){return A.d<B.d;}
int main(){
//freopen("a.in","r",stdin);
n=read();
for(int i=1;i<=n;i++)cin>>a[i].d;
for(int i=1;i<=n;i++)cin>>a[i].v;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i].v>a[j].v)ans++;
}
}
cout<<ans;
return 0;
}

解法2:智障的set(40pts)

先介绍个函数:\(algorithm\)库里的\(distance\)函数能够轻易的帮我们把迭代器转成下标处理,用到set上就十分合适

利用set自动排序的功能,可以轻易处理逆序对,将位置从大到小\(sort\)一遍,找新序列的正序对就行了(正序是逆序对,倒序不就是正序对么)

如果新元素比队尾元素大,说明前面所有元素都能于它构成正序对,相反,就可以利用\(lowerbound\)函数找到第一个大于等于它的位置,恰好是它能组成的正序对个数

但是由于set时间效率极低,还没暴力跑的快,用这个练习练习STL就行了

代码:



/*#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
name=$GEDIT_CURRENT_DOCUMENT_NAME
pre=${name%.*}
g++ -O2 $dir/$name -o $pre -g -Wall -std=c++11
if test $? -eq 0; then
gnome-terminal -x bash -c "time $dir/$pre;echo;read;"
fi*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
typedef long long ll;
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,f[maxn];
ll ans;
struct Node{
ll d,v;
}a[maxn];
multiset<int> s;
bool cmp(Node A,Node B){return A.d>B.d;}
int main(){
// freopen("a.in","r",stdin);
n=read();
for(int i=0;i<n;i++)cin>>a[i].d;
for(int i=0;i<n;i++)cin>>a[i].v;
sort(a,a+n,cmp);
s.insert(a[0].v);
f[0]=0;
for(int i=1;i<n;i++){
int len=s.size();
if(a[i].v>=*s.rbegin()){//注意,set的end()是假的,只能这样求队尾元素
f[i]=len,s.insert(a[i].v);
}else{
// cout<<(lower_bound(ve.begin(),ve.end(),a[i].v),a[i].v)<<endl;
f[i]=distance(s.begin(),s.lower_bound(a[i].v));//distance将迭代器转下标
s.insert(a[i].v);
}
//for(int i=0;i<n;i++)cout<<ve[i]<<" ";
//cout<<endl;
}
for(int i=0;i<n;i++)ans+=f[i];
cout<<ans;
return 0;
}

解法3:vector模拟set(100pts)

众所周知,$$vector功能强大,轻易就能排个序,效率比set还高不少,但是终究过不了加强版的P1908

代码:



/*#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
name=$GEDIT_CURRENT_DOCUMENT_NAME
pre=${name%.*}
g++ -O2 $dir/$name -o $pre -g -Wall -std=c++11
if test $? -eq 0; then
gnome-terminal -x bash -c "time $dir/$pre;echo;read;"
fi*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
typedef long long ll;
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,f[maxn];
ll ans;
struct Node{
ll d,v;
}a[maxn];
vector<int> ve;
bool cmp(Node A,Node B){return A.d>B.d;}
int main(){
// freopen("a.in","r",stdin);
n=read();
for(int i=0;i<n;i++)cin>>a[i].d;
for(int i=0;i<n;i++)cin>>a[i].v;//狗比vector只能从0开始存
sort(a,a+n,cmp);
ve.push_back(a[0].v);
f[0]=0;
for(int i=1;i<n;i++){
int len=ve.size();
if(a[i].v>=ve.back()){
f[i]=len,ve.push_back(a[i].v);
}else{
// cout<<(lower_bound(ve.begin(),ve.end(),a[i].v),a[i].v)<<endl;
f[i]=lower_bound(ve.begin(),ve.end(),a[i].v)-ve.begin();//注意写法,考试就在这被卡住了
ve.insert(lower_bound(ve.begin(),ve.end(),a[i].v),a[i].v);//假装排序
}
//for(int i=0;i<n;i++)cout<<ve[i]<<" ";
//cout<<endl;
}
for(int i=0;i<n;i++)ans+=f[i];
cout<<ans;
return 0;
}

解法4:树状数组(100pts)

对结构体\(a[i]\)排序,按位置从小到大的顺序排,利用辅助数组b记录排序后的位置,将位置插入树状数组,咨询一下后缀和即可

代码:



/*#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
name=$GEDIT_CURRENT_DOCUMENT_NAME
pre=${name%.*}
g++ -O2 $dir/$name -o $pre -g -Wall -std=c++11
if test $? -eq 0; then
gnome-terminal -x bash -c "time $dir/$pre;echo;read;"
fi*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
typedef long long ll;
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,f[maxn];
ll ans,b[maxn],c[maxn];
struct Node{
ll d,v;
}a[maxn];
bool cmp(Node A,Node B){return A.d<B.d;}
ll Lowbit(ll x){return x&-x;}
void update(ll x){
while(x<=n){
c[x]++;
x+=Lowbit(x);
}
}
ll query(ll x){
ll sum=0;
while(x){
sum+=c[x];
x-=Lowbit(x);
}
return sum;
}
int main(){
//freopen("a.in","r",stdin);
n=read();
for(int i=1;i<=n;i++)cin>>a[i].d;
for(int i=1;i<=n;i++)cin>>a[i].v,b[i]=a[i].v;
sort(a+1,a+n+1,cmp);
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)a[i].v=lower_bound(b+1,b+1+n,a[i].v)-b;
for(int i=n;i>=1;i--){
ans+=query(a[i].v-1);update(a[i].v);
}
cout<<ans;
return 0;
}

解法5:归并排序(100pts)

这就不用写了吧,归并能处理逆序对(貌似也只有这个用途)

「杂烩」精灵魔法(P1908逆序对弱化版)的更多相关文章

  1. 「luogu2387」[NOI2014] 魔法森林

    「luogu2387」[NOI2014] 魔法森林 题目大意 \(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{ ...

  2. 洛谷P1908 逆序对

    P1908 逆序对 2.2K通过 4.4K提交 题目提供者该用户不存在 标签云端 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 归并排序党注意了!数组要开… ...

  3. 洛谷P1908 逆序对【递归】

    题目:https://www.luogu.org/problemnew/show/P1908 题意:给定一个数组,求逆序对个数. 思路: 是一个很经典的题目了.通过归并排序可以求逆序对个数. 现在有一 ...

  4. P1908 逆序对-(树状数组)

    https://www.luogu.org/problem/P1908 比较喜欢线段树,懒得用树状数组(只会套模板,位运算的精髓没有领悟到),一直没有记录树状数组代码,又得捡回来,趁这道题记录一下模板 ...

  5. P1908 逆序对-(cdq分治)

    https://www.luogu.org/problem/P1908 沿用归并排序的思想求逆序对. 坑1:结果爆int型,需要用longlong 坑2:相对于归并排序,在比较的时候多了一个等号 举例 ...

  6. P1908 逆序对(归并排序)

    https://www.luogu.com.cn/problem/P1908 归并排序是用来求逆序对的 归并排序的思想就是分治 #include <bits/stdc++.h> using ...

  7. P1908 逆序对——树状数组&离散化&快读快写の学习

    题目简述: 对于给定的一段正整数序列,逆序对就是序列中 a_i>a_jai​>aj​ 且 i<ji<j 的有序对. 输出序列中逆序对的数目. 知识补充: 树状数组: 这东西就是 ...

  8. 洛谷 P1908 逆序对 Label:归并排序||树状数组 不懂

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  9. 洛谷 P1908 逆序对

    \[传送门qwq\] 题目描述 猫猫\(TOM\)和小老鼠\(JERRY\)最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计. 最近,\(TOM\)老猫查阅 ...

随机推荐

  1. java实现第六届蓝桥杯打印菱形

    打印菱形 给出菱形的边长,在控制台上打印出一个菱形来. 为了便于比对空格,我们把空格用句点代替. 当边长为8时,菱形为: .......* ......*.* .....*...* ....*.... ...

  2. 哪些年,我们玩过的Git

    作者:玩世不恭的Coder公众号:玩世不恭的Coder时间:2020-06-05说明:本文为原创文章,未经允许不可转载,转载前请联系作者 哪些年,我们玩过的Git 前言一.前期工作常用基本概念的理解G ...

  3. sqlite使用dbexpress时数据库不存在自动建立数据库

    在发布使用delphi dbexpress编写的基于SQLITE的程序时,需要在运行时判断某个数据库是否存在,如果不存在,则自动建立. 方法有2,其中之一是判断数据库文件是否存在,如果不存在,则创建一 ...

  4. 钻进 Linux 内核看个究竟

    Linux 内核,这个经常听见,却不不知道它具体是干嘛的东西,是不是觉得非常神秘? Linux 内核看不见摸不着,而对于这类东西,我们经常无从下手.本文就以浅显易懂的语言,带你钻进 Linux 内核, ...

  5. OSI七层模型及各层作用

    物理层:建立.维护.断开物理连接 数据链路层:该层的作用包括了物理地址寻址,数据的成帧,流量控制,数据的检错,重发等.该层控制网络层与物理层之间的通信,解决的是所传输数据的准确性的问题.为了保证传输, ...

  6. Spring-AOP之工作实践(一)

    案例一.角色校验 项目中,对某些方法需要用户具备指定角色权限才能执行. /** * 角色校验注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(Elem ...

  7. Elasticsearch原理入门

    这是一篇拼接贴,我是缝合怪 项目中用到了es,使用方法是挺简单的,封装了基本api以后,把查询条件封装一下传给client执行就可,但是光使用比较肤浅,研究一下原理和本质,更利于以后开发使用 扫盲贴 ...

  8. numpy矩阵相加时需注意的一个点

    今天在进行numpy矩阵相加的时候出现了一个小的奇怪的地方,下面我们来看看: >>>P = np.array([1,2,3,4]) >>>F = np.array( ...

  9. class 类组件:

    ES6  中的class 类组件: // class 关键字:确定一个类型student以类的概念存在 class student{ //构造函数 是默认自动执行 // 初始化 name age 属性 ...

  10. Java 重写hashCode()与equals()

    为什么要重写hashCode() 和 equals() equals() 默认的Object类里面equals()方法是根据对象所在的内存来做判断的,如果两个对象引用指向的是同一个内存,则返回true ...