[洛谷P1966] 火柴排队
题目链接:
题目分析:
感觉比较顺理成章地就能推出来?似乎是个一眼题
交换的话多半会往逆序对上面想,然后题目给那个式子就是拿来吓人的根本没有卵用
唯一的用处大概是告诉你考虑贪心一波,很显然有两个序列中每对排名对应的数放在同一位置上是最优策略这个结论
说详细一点,假设\(a_0\)是\(a\)序列中的第\(k\)大,\(b_0\)是\(b\)序列中的第\(k\)大,那么\(a_0\)和\(b_0\)肯定需要交换到同一个位置上,然后相减。
然后我们考虑怎么交换次数最少
先考虑最简单粗暴的交换方法:两个序列分别排个序,这样排名肯定一一对应
这样的话交换次数是两个序列中逆序对数量之和
但是这样并不是最优的,比如说两个序列中的排名可以都是1423。如果我们直接排序,会出现我们本来进行一次交换就能搞定的一对数,为了把他换到排名相符的地方去,又一起往前换了(比如两个序列都已经1423了,但是如果直接排序就会有4和2再进行一下不必要的交换这样的情况),这对答案其实是没有贡献的
然后我们考虑怎样优化
首先发现其实问题和这个数本身没什么关系,主要是和数的排名有关系,所以可以先把数组离散化
然后就是我也不知道自己怎么想到的了……先把第一个序列的每个数优先级重新定义一下
比如说
1 3 4 2
我们把它每个元素的优先级定义成
1 2 3 4
1 3 4 2
(上下对应的)
然后我们用我们自己定义的优先级重新定义第二个序列,假设第二个是
1 4 2 3
然后我们把它替换成
1 3 4 2
这样我们得到新的两个序列是
1 2 3 4
1 3 4 2
保证第一个序列不动,这个时候就交换第二个序列的元素来和第一个的排名匹配上就可以了(因为换第一个和换第二个其实本质上没有差别)
交换次数就是第二个序列里的逆序对数,归并排序或者树状数组
代码:
实现不难,我写的归并,这个代码因为是赶时间写的长得很丑,重点在上面分析
#include <bits/stdc++.h>
#define int long long
#define N (100000 + 20)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
int n, a[N], b[N << 1], a_[N], res, cnt, ans;
int New[N];
void Discretization(int a[]) {
sort(b + 1, b + n + 1);
int q = unique(b + 1, b + n + 1) - b;
for (register int i = 1; i <= n; i++)
a[i] = lower_bound(b + 1, b + q + 1, a[i]) - b - 1;
}
int merge(int l, int r) {
int mid = (l + r) >> 1;
int i = l, j = mid + 1; cnt = 0;
for (register int k = l; k <= r; k++)
if (j > r || (i <= mid && a_[i] < a_[j])) b[k] = a_[i++];
else b[k] = a_[j++], cnt += (mid - i + 1) % 99999997;
for (register int k = l; k <= r; k++) a_[k] = b[k];
return cnt;
}
int solve(int l, int r) {
if (l < r) {
int mid = (l + r) >> 1;
solve(l, mid), solve(mid + 1, r);
ans += merge(l, r);
}
return ans;
}
signed main() {
n = read();
for (register int i = 1; i <= n; i++) a[i] = b[i] = read();
Discretization(a);
for (register int i = 1; i <= n; i++) a_[i] = b[i] = read();
Discretization(a_);
for (register int i = 1; i <= n; i++) New[a[i]] = i;
for (register int i = 1; i <= n; i++) a_[i] = New[a_[i]];
// for (register int i = 1; i <= n; i++) cout<<a_[i]<<" ";
// cout<<endl;
memset(b, 0, sizeof(b));
res = solve(1, n) % 99999997;
printf("%d", res % 99999997);
return 0;
}
[洛谷P1966] 火柴排队的更多相关文章
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
[NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...
- 【刷题】洛谷 P1966 火柴排队
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
- 洛谷 P1966 火柴排队 解题报告
P1966 火柴排队 题目描述 涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: \(\s ...
- 洛谷——P1966 火柴排队&&P1774 最接近神的人_NOI导刊2010提高(02)
P1966 火柴排队 这题贪心显然,即将两序列中第k大的数的位置保持一致,证明略: 树状数组求逆序对啦 浅谈树状数组求逆序对及离散化的几种方式及应用 方法:从前向后每次将数插入到bit(树状数组)中, ...
- 洛谷 P1966 火柴排队
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:∑(ai−bi)2 其中ai 表示 ...
- 洛谷 P1966 火柴排队 —— 思路
题目:https://www.luogu.org/problemnew/show/P1966 首先,一个排列相邻交换变成另一个排列的交换次数就是逆序对数: 随便画一画,感觉应该是排个序,大的对应大的, ...
- 洛谷——P1966 火柴排队
https://www.luogu.org/problem/show?pid=1966 题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列 ...
- 洛谷p1966 火柴排队 (逆序对变形,目标排序
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
- 洛谷P1966 火柴排队 贪心+离散化+逆序对(待补充QAQ
正解: 贪心+离散化+逆序对 解题报告: 链接在这儿呢quq 这题其实主要难在想方法吧我觉得?学长提点了下说用贪心之后就大概明白了,感觉没有很难 但是离散化这里还是挺有趣的,因为并不是能很熟练地掌握离 ...
随机推荐
- sklearn参数优化
学习器模型中一般有两个参数:一类参数可以从数据中学习估计得到,还有一类参数无法从数据中估计,只能靠人的经验进行指定,后一类参数就叫超参数 比如,支持向量机里的C,Kernel,gama,朴素贝叶斯里的 ...
- codeforces round#524 C. Masha and two friends /// 矩形切割
题目大意: 给定n行m列的黑白棋盘如下 给定矩形的左下点x1 y1和右上点x2 y2将这个区域都涂成白色 再给定矩形的左下点x3 y3和右上点x4 y4将这个区域都涂成黑色 求最后棋盘内有分别多少个白 ...
- Mybatis 使用Mapper接口的Sql动态代码方式进行CURD和分页查询
1.Maven的pom.xml 2.配置文件 2.1.db.properties 2.2.mybatis.xml 2.3.log4j.xml 3.MybatisUtil工具类 4.Mapper映射文件 ...
- ionic js 滑动框ion-slide-box 滑动框是一个包含多页容器的组件,每页滑动或拖动切换
ionic 滑动框 ion-slide-box 滑动框是一个包含多页容器的组件,每页滑动或拖动切换: 效果图如下: 用法 <ion-slide-box on-slide-changed=&quo ...
- 4、Docker网络访问
现在我们已经可以熟练的使用docker命令操作镜像和容器,并学会了如何进入到容器中去,那么实际的工作中,我们通常是在Docker中部署服务,我们需要在外部通过IP和端口进行访问的,那么如何访问到Doc ...
- win10安装mysql__艰难的心路历程
俺是新系统,嘿嘿嘿 首先,把下载好的压缩包解压到安装目录中,哪个盘可以. 第二,先创建my.ini文件,不然待会忘了.在文件中添加以下内容: [mysqld] port = basedir=C:\Wi ...
- 使用line-height垂直居中在安卓手机上效果不好
前端实现单行垂直居中用的最多的方法可能就是line-height了吧.该属性在pc端和ios手机上效果都很好,可到了安卓手机,有很大几率发生文字上移的现象 知乎有人分析了导致这一现象的原因,Andro ...
- Jupyter notebook文件默认存储路径以及更改方法
1.文件默认存储路径怎么查? 安装Anaconda后,新建文件的默认存储路径一般在C系统盘,那么路径是什么呢? 首先,新建一个.ipynb文件, 输入以下脚本,运行出的结果即是当前jupyter文件 ...
- Java基本语法.part02
变量 变量的概念: 内存中的一个存储区域 该区域有自己的名称(变量名)和类型(数据类型) Java中每个变量必须先声明,后使用 该区域的数据可以在同一类型范围内不断变化 使用变量注意: 变量的作用域: ...
- Spring整合Dubbo框架
Dubbo作为一个RPC框架,其最核心的功能就是要实现跨网络的远程调用.演示过程创建两个小工程,一个作为服务的提供者,一个作为服务的消费者.通过Dubbo来实现服务消费者远程调用服务提供者的方法. d ...