[NOIP2013 提高组] 火柴排队

题目描述

涵涵有两盒火柴,每盒装有 nnn 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:$ \sum (a_i-b_i)^2$

其中 aia_iai​ 表示第一列火柴中第 iii 个火柴的高度,bib_ibi​ 表示第二列火柴中第 iii 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 108−310^8-3108−3 取模的结果。

输入格式

共三行,第一行包含一个整数 nnn,表示每盒中火柴的数目。

第二行有 nnn 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 nnn 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式

一个整数,表示最少交换次数对 108−310^8-3108−3 取模的结果。

样例 #1

样例输入 #1

4
2 3 1 4
3 2 1 4

样例输出 #1

1

样例 #2

样例输入 #2

4
1 3 4 2
1 7 2 4

样例输出 #2

2

提示

【输入输出样例说明一】

最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2根火柴。

【输入输出样例说明二】

最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2根火柴的位置。

【数据范围】

对于 10%10\%10% 的数据, 1≤n≤101 \leq n \leq 101≤n≤10;

对于 30%30\%30% 的数据,1≤n≤1001 \leq n \leq 1001≤n≤100;

对于 60%60\%60% 的数据,1≤n≤1031 \leq n \leq 10^31≤n≤103;

对于 100%100\%100% 的数据,1≤n≤1051 \leq n \leq 10^51≤n≤105,0≤0 \leq0≤ 火柴高度 <231< 2^{31}<231。

题解

首先得出,a数列中第几大的数和b数列中第几大的数要上下对应。

也就是说我们要以一行位模板串,以它的排序方式为规则,所以要用到数组q,以a[i]为关键字对b排序。

这里是以b[i]为关键字对a排序的,当两个序列相同时,比如当i = 1时,c[b[i]] = a[i]。
也就是c数组的下标和数值相等,代表a[i] = b[i]。当c数组出现逆序对的时候,说明有a[i]!=b[i]。
把要比较的两个量放在一个数组里,利用逆序对的方式去计算有几个数据不同是这题的特性

我们存一个数组c[i];c[B[i]编号]=A[i]编号;A:2 3 1 4->1 2 3 4对应原编号为:3 1 2 4B:3 2 1 4->1 2 3 4对应原编号为:3 2 1 4c[B[1]编号]=c[3]=a[1]编号=3c[B[2]编号]=c[2]=a[2]编号=1c[B[3]编号]=c[1]=a[3]编号=2c[B[4]编号]=c[4]=a[4]编号=4于是c[1]=2 c[2]=1 c[3]=3 c[4]=4逆序对数=1,交换一次。

问题转化为求c数组中逆序对的个数问题转化为求c数组中逆序对的个数问题转化为求c数组中逆序对的个数

题目要求相邻交换,用归并排序 ororor(树状排序)来算逆序对的个数。

在此之前,观察到数据范围比较大,要用离散化压缩一下空间。

归并排序

#include<bits/stdc++.h>using namespace std;typedef struct n{int num,ord;}node;node first_team[100010],second_team[100010];int a[100010],b[100010],ans;int compare(node x,node y){return x.num < y.num;}void Merge(int l,int r){if(l>=r) return ;int mid=(l+r)/2;Merge(l,mid);Merge(mid+1,r);int i=l,j=mid+1,k=l;while(i<=mid&&j<=r){if(a[i]>a[j]){b[k++]=a[j++];ans+=mid-i+1;ans%=99999997;}else b[k++]=a[i++];}while(i<=mid) b[k++]=a[i++];while(j<=r) b[k++]=a[j++];for(int i=l;i<=r;i++)a[i]=b[i];}int main(){int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&first_team[i].num);first_team[i].ord=i;}for(int i=1;i<=n;i++){scanf("%d",&second_team[i].num);second_team[i].ord=i;}sort(first_team+1,first_team+n+1,compare);sort(second_team+1,second_team+n+1,compare);for(int i=1;i<=n;i++)a[first_team[i].ord]=second_team[i].ord;Merge(1,n);printf("%d",ans);return 0;}

树状数组

解释

树状数组就是维护区间和的一种解法,因为本题要知道在一个数前面有多少数能与它组成逆序对,所以适应树状数组的特性。

图片解释来自https://www.luogu.com.cn/blog/ryoku/solution-p1908

6

5 4 2 6 3 1

1)进行离散化操作,处理数据(这里储存的是在数组中是第几大的):a[]={2,3,5,1,4,6}

2)然后加入a1 = 2,(即2的位置上放了一个数) ,ans=0,目前数组中小于a1的全部可以和a1组成逆序对

3)加入 a2=3 ans=1 同上

4)加入 a3=5 ans=3

5)加入 a4=1 ans=3

6)加入 a5=4 ans=6

6)加入 a6=6 ans=11

树状数组求逆序对的模板,也是来自同一作者
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,c[40005]={0},a[40005]={0},b[40005]={0};  //定义数组,b[]为读入的数组,a[]为要离散化后的数组,C[]为树状数组
inline void Add(register int x)  //树状数组加入
{for(;x<=n;x+=(x&-x))c[x]++;  //因为这里只需要1,所以我就写出c[x]++了
}
inline int Sum(register int x)  //树状数组求和,同上面的sum(x)
{register int s=0;  //计数的变量for(;x>0;x-=(x&-x))  //累计s+=c[x];return s;  //返回结果
}
bool cmp1(const int &x,const int &y)  //离散化需要用的,上面有讲
{return b[x]>b[y];
}
int main()
{int ans=0;  //ans为最后的结果scanf("%d",&n);  //读入nfor(register int i=1;i<=n;i++){scanf("%d",&b[i]);  //读入a[i]=i;  //顺便初始化一下a数组}sort(a+1,a+n+1,cmp1);  //给a数组排序,达到最终的效果for(register int i=1;i<=n;i++){Add(a[i]);  //依次加入树状数组ans+=Sum(a[i]-1);  //计算结果并累计}printf("%d",ans);  //输出ansreturn 0;  //返回
}

关于本题的代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
const int maxm = 99999997;
struct MyStruct
{int data;int loc;
}a[maxn],b[maxn];
int e[maxn], n, c[maxn];
int inline readint()
{int x = 0;char c = getchar();while (c<'0' || c>'9') c = getchar();while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x;
}
int lowbit(int x)
{return x&-x;//树状数组实现
}
void add(int x,int t)
{while (x <= n){e[x] += t;e[x] %= maxm;x += lowbit(x);//每次往后加,可以改变后面对应的和 }
}
int sum(int x)
{int s = 0;while(x){s += e[x];s %= maxm;x -= lowbit(x);//得到所求的和 }return s;
}
bool cmp(MyStruct x, MyStruct y)
{return x.data < y.data;
}
int main()
{n = readint();for (int i = 1; i <= n; i++){a[i].data = readint();a[i].loc = i;//记录位置 }for (int i = 1; i <= n; i++){b[i].data = readint();b[i].loc = i;}sort(a + 1, a + n + 1, cmp);sort(b + 1, b + n + 1, cmp);for (int i = 1; i <= n; i++){c[a[i].loc] = b[i].loc;//离散优化 }int ans = 0;for (int i = 1; i <= n; i++){add(c[i], 1);//离散优化后大小就是正确顺序的位置 ans += i - sum(c[i]);/*i是a的当前位置,sum(c[i])表示c[i]前有几个位置(c[i]应该排在第几个位置)差即为要移动的位置 举例:i = 1c[i] = 5,sum(5) = 1,i - sum(5) = 0.   5 3 2 1 4i = 2c[i] = 3,sum(3) = 1,i - sum(3) = 1.   3 5 2 1 4i = 3c[i] = 2,sum(2) = 1,i - sum(2) = 2.   2 3 5 1 4i = 4c[i] = 1,sum(1) = 1,i - sum(1) = 3.   1 2 3 5 4i = 5c[i] = 1,sum(c[i]) = 4,i - sum(c[i]) = 1. 1 2 3 4 5移动火柴有一定的规则要将下面的逆序对全部消除应该怎么移动:5 4 1 2 35 1 4 2 31 5 4 2 31 5 2 4 31 2 5 4 31 2 5 3 41 2 3 5 41 2 3 4 5由上面的过程可以发现对于每一个小的数,我们都要把他提上来,提的次数取决于它的前面有几个数比他大,和移动火柴的限制要求恰好相似。*/ans %= maxm;}printf("%d", ans);return 0;
}

每次+ 或 *都要取模。

[NOIP2013 提高组] 火柴排队相关推荐

  1. 【NOIP2013提高组】火柴排队

    题目背景 NOIP2013 提高组 Day1 试题 题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定 ...

  2. NOIP2013 提高组复赛解题报告

    NOIP2013 提高组复赛 day1 day\;1 1002. 火柴排队 贪心+数据结构/归并排序 这个"相邻交换"让我联想到了NOIP2012_day1_task2_game那 ...

  3. 【题解】P1979 [NOIP2013 提高组] 华容道(SPFA,BFS,常数优化)

    [题解]P1979 [NOIP2013 提高组] 华容道 最近打比赛次次挂..平均每周得被至少一场比赛打击一次(这周好不容易 ABC 打的还行模拟赛又挂--)心烦意乱.写篇题解疏散一下内心的苦闷(雾) ...

  4. P1149 [NOIP2008 提高组] 火柴棒等式——暴力枚举

    [NOIP2008 提高组] 火柴棒等式 题目描述 给你 n n n 根火柴棍,你可以拼出多少个形如 A + B = C A+B=C A+B=C 的等式?等式中的 A A A. B B B. C C ...

  5. 【NOIP2013提高组】花匠

    题目背景 NOIP2013 提高组 Day2 试题. 题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空 ...

  6. P1979 [NOIP2013 提高组] 华容道

    题目来源 [NOIP2013 提高组] 华容道 - 洛谷 题目考点 搜索   图论 题目 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, ...

  7. 【NOIP2013提高组】积木大赛

    题目背景 NOIP2013 提高组 Day2 试题 题目描述 春春幼儿园举办了一年一度的"积木大赛".今年比赛的内容是搭建一座宽度为 n 的大厦,大厦可以看成由 n 块宽度为 1  ...

  8. 【NOIP2013提高组T3】加分二叉树

    题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,-,n),其中数字1,2,3,-,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都 ...

  9. [NOIP2013提高组] CODEVS 3287 火车运输(MST+LCA)

    一开始觉得是网络流..仔细一看应该是最短路,再看数据范围..呵呵不会写...这道题是最大生成树+最近公共祖先.第一次写..表示各种乱.. 因为要求运输货物质量最大,所以路径一定是在最大生成树上的.然后 ...

  10. [NOIP2013][逆序对]火柴排队

    题目: 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示第 ...

最新文章

  1. 由浅入深,走进Python装饰器-----第五篇:进阶--类装饰类
  2. 深度洞见|一文详解 2022 数字营销的变与不变
  3. deepin关闭ACPI
  4. 奇迹暖暖服务器不稳定,闪耀暖暖用土豆当服务器?开服仅半小时就崩溃,无数玩家疯狂吐槽...
  5. 数据镜像备份工具rsync
  6. “QQ尾巴病毒”核心技术的实现
  7. “阿里离职女高管”二次回应质疑:晒股票、期权等证据
  8. leetcode 318 最大单词长度乘积
  9. 促促促,如何确保系统扛得住 | 《尽在双11》抢鲜预览
  10. 光干涉波谷,有可能低于绝对零度
  11. python写给初学者的一封信
  12. 基于Java-EE和websocket的无人机网页监控系统(网页地面站-源码)
  13. DELPHI 编程(一) __快速认识Delphi
  14. 爱心的数学函数方程_数学里有哪些可以示爱的图像?它们的函数方程又是什么?...
  15. 三菱FX5U常见问题解析
  16. 学习笔记——STM32摄像头OV7725(一)
  17. Gluster部署案例
  18. 使用python绘制标准心形线
  19. 以核心素养为导向的计算机教学方式,核心素养导向的课堂教学-感悟
  20. Jenkins - cannot find symbol

热门文章

  1. TP5和TP3.2区别
  2. Pyecharts树状图:树图
  3. 西游记中孙悟空被唐僧赶走的三回
  4. speedoffice使用方法-word怎么快速分页呢
  5. IMO班聊助力壹米滴答全国“织网” 让每一米、每一秒都更有效率
  6. 如何成为一名优秀的网络信息安全工程师?
  7. python中‘ ‘.join()的使用
  8. 如何确定网站的关键词呢
  9. 2019东北四省 H. Skyscraper (树状数组)
  10. 上海私车牌价狂降3万余元!!!