NOIP 2013 火柴排队
洛谷 P1966 火柴排队
JDOJ 2227: [NOIP2013]火柴排队 D1 T2
Description
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑i=1n(ai−bi)2,其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
Input
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
Output
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
Sample Input
Sample Input I: 4 2 3 1 4 3 2 1 4 Sample Input II: 4 1 3 4 2 1 7 2 4
Sample Output
Sample Output I: 1 Sample Output II: 2
HINT
【样例1说明】
最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。
【样例2说明】
最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。
【数据范围】
对于 10%的数据, 1 ≤ n ≤ 10;
对于 30%的数据,1 ≤ n ≤ 100;
对于 60%的数据,1 ≤ n ≤ 1,000;
对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ 231 − 1。
Source
题解:
这是一道求逆序对的题目;
求逆序对的手段有的时候是次要的,我们首先要弄明白为什么这道题是求逆序对的题。
那么让我来概括一下题目大意:
让你把两列火柴排一下队,使得俩队列中序号相同的两根火柴的高度差值最小。
然鹅,最终要求的竟然不是最小差值,而是差值最终需要交换多少次//%%%
所以我们得出这个结论,这两列火柴必须是最大匹配最大,次大匹配次大,以此类推,才能得出最小差值。
再看看题目中要求只能交换相邻的两个火柴的位置,所以我们想到了求逆序对个数。
那么我们开始回头看逆序对咋求。
1、归并排序
2、树状数组
3、暴力(想到这种方法的当场打死)
都挺简单的,因为我是在树状数组板块中学的逆序对,所以我使用了树状数组求逆序对。
如果通过逆序对本身的定义来理解的话,我们会发现:这个逆序对不应该用树状数组求啊?但是人类的智力是无极限的,我们回顾一下树状数组的用途,发现这个玩意是用来区间求和的,也就是说,这个东西只能裸的求和?
那未免太辱没它的名头了。
我们这样想,树状数组在求逆序对的时候只是一个求和的工具,我们可以通过树状数组来求当前这个数所在位置前面比它大的数的个数,就可以方便的统计逆序对的个数。
所以我们考虑把每个火柴定义一个结构体,一个存编号,也就是位置,一个存长度。最后我们按照长度由小到大排序(当然由大到小也可以),最后我们进行整个程序也是思路中最重要的点:离散化。
简单介绍一下离散化。这算是一种常用的小技巧,适用于什么情况呢?就是我们在解题过程中只在意这个数的大小关系,而不在意这个数到底是多大。我们可以形象地理解一下,现在有5个数分布在1-10000000的区间内,我们只需要知道他们到底多大,所以我们建一个离散化数组D[],其中D[i]表示第i个元素在其中排第j位,这个j最大也只是5.
这个过程就叫做离散化。
显然这道题适用离散化。
所以我们将数据离散化之后,就可以进行树状数组的处理,其中树状数组函数getsum(sum[i])就表示比高度为i的元素大的数的个数。
然后统计ans的时候要记得ans+=i-getsum(sum[i]);表示当前位置减去比当前位置大的所有元素的个数。
注意每次操作的时候都取模。
AC code:
#include<cstdio>
#include<algorithm>
#define mod 99999997
using namespace std;
struct node
{
int h,order;
}a[100010],b[100010];
int c[100010],sum[100010],n,ans;
bool cmp(node a,node b)
{
return a.h<b.h;
}
void fix(int x)
{
for(int i=x;i<=n;i+=i&-i)
c[i]++,c[i]%=mod;
}
int getsum(int x)
{
int ret=0;
for(int i=x;i;i-=i&-i)
ret+=c[i],ret%=mod;
return ret;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].h);
a[i].order=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i].h);
b[i].order=i;
}
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
sum[a[i].order]=b[i].order;
for(int i=1;i<=n;i++)
{
fix(sum[i]);
ans+=i-getsum(sum[i]);
ans%=mod;
}
printf("%d",ans);
return 0;
}
NOIP 2013 火柴排队的更多相关文章
- 【NOIP】提高组2013 火柴排队
[题意]两列n个火柴,分别有高度ai和bi(同一列高度互不相同),每次可以交换一列中的两个相邻火柴,定义距离为∑(ai-bi)^2,求使距离最小的最少交换次数,n<=10^5. [算法]逆序对 ...
- Codevs 3286 火柴排队 2013年NOIP全国联赛提高组 树状数组,逆序对
题目:http://codevs.cn/problem/3286/ 3286 火柴排队 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : ...
- NOIP 2013 T2 火柴排队 ---->求逆序对
[NOIP2013T2]火柴排队 背景 noip2013day1 描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各 自 排成一列, 同一列火柴的高度互不相同, ...
- NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】
NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...
- NOIP 2013
Prob.1 转圈游戏 找到循环节,然后快速幂.代码: #include<cstdio> #include<cstring> #include<iostream> ...
- 洛谷P1966 【火柴排队】
题解 P1966 [火柴排队] 说明: 在数学中有个公式: (a1-b1)^2+(a2-b2)^2<(a2-b1)^2+(a1-b2)^2 (你可以自己试着证一下) 两列火柴对应的两根火柴在各列 ...
- [树状数组+逆序对][NOIP2013]火柴排队
火柴排队 题目描述 涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑ (ai-bi)2,i=1,2,3,. ...
- Luogu 1979 NOIP 2013 华容道(搜索,最短路径)
Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...
- noip 2013 提高组 day1
1.转圈游戏: 解析部分略,快速幂就可以过 Code: #include<iostream> #include<fstream> using namespace std; if ...
随机推荐
- js中的super
1.this和super的区别: this关键词指向函数所在的当前对象 super指向的是当前对象的原型对象 2.super的简单应用 const person = { name:'jack' } c ...
- Python 中 如何将两个列表元素一一对应成字典
使用python的 zip函数 和强大的集合操作可以方便的将两个list元素一一对应转换为dict,如下示例代码: names = ['n1','n2','n3'] values = [1,2,3] ...
- 关于wepy小程序图片显示问题
如果图片资源在本地,用background-image 是无法找到本地资源的,只能通过image标签用src进行引入: 图片资源在服务器上,用背景图片和image进行引入,在安卓真机上测试是没有问题的 ...
- 在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步 ctrl+alt+右 回到下一步
在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步ctrl+alt+右 回到下一步
- Rider中Winform开发支持预览(5)
1.Rider .netCore3.0 winform设计器支持预览,这点vs目前还不支持. 2.不过winform下控件选择工具栏都是没有图标的
- 源码分析-----ThreadPoolExecutor
创建一个线程池: import time from concurrent.futures import ProcessPoolExecutor, as_completed def get_html(n ...
- 『optimization 动态规划』
optimization Description \(visit\_world\) 发现有些优化问题可以用很平凡的技巧解决,所以他给你分享了这样一道题: 现在有一个长度为N的整数序列\(\{a_i\} ...
- [原创]SpringSecurity控制授权(鉴权)功能介绍
1.spring security 过滤器链 spring security中的除了用户登录校验相关的过滤器,最后还包含了鉴权功能的过滤器,还有匿名资源访问的过滤器链,相关的图解如下: 2.控制授 ...
- Spring aop的一些小知识点总结
1 Spring的aop无法拦截静态方法 2 在 proxyTargetClass = false时 对于实现了接口的bean,则只有接口中的方法会被拦截: 对于没有实现任何接口的bean,publi ...
- SUSE 中文是乱码
http://www.wo81.com/tec/os/suse/2014-04-30/186.html 操作系统:SUSE Linux Enterprise 11 问题:vi 打开文件,中文是乱码 ...