传送门

Description

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

其中$ a_i$ 表示第一列火柴中第$ i $个火柴的高度,$b_i$表示第二列火柴中第 $i$ 个火柴的高度。

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

## Input

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

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

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

## Output

一个整数,表示最少交换次数对 $99,999,997$ 取模的结果。

## Sample Input
```
4
2 3 1 4
3 2 1 4
```
## Sample Output
```
1
```
## Hint
对于 $100\%$的数据,$1 ≤ n ≤ 100,000,0 ≤$火柴高度$≤ maxlongint$
## Solution
和[NOIP2011D2T1聪明的质检员](https://www.cnblogs.com/yifusuyi/p/9531622.html)一样,既然题目给了一个表达式并且瞪眼看不出这个式子有啥可做的,那么就化简这个式子。

把式子平方展开,则$ \sum (a_i-b_i)2~=~\sum~a_i2+\sumb_i^2+2\times\suma_i*b_i$。

显然\(\sum~a_i^2~+~\sum~b_i^2\)已经固定了,所以我们要做的是最小化\(\sum~a_i*b_i\)

根据排序不等式,上式最小当且仅当\(\forall i\),a,b第\(i\)大的数在同一位置。

那么我们按照\(a_i\)的顺序给\(b_i\)排序。即新建一个序列\(C\),将a,b离散化后使得\(C\)满足\(C_{a_i}=b_i\)。它的数学意义是\(a\)中第i大的数对应位置上\(b\)的大小。

显然,达到合法的情况应该满足\(\forall i,C_i=i\)。

显然一起移动A,B和只移动B是等价的,那么本题就变为交换\(C\)中相邻元素用最少的步数满足\(C\)中元素按照升序排序。

咦?这不就是逆序对嘛?

其实我也是才知道这就是逆序对的意义

证明可以使用数学归纳法。

先将最大的元素移动到后面去。显然元素列他后面都是都是比他小的,所以把他移动到最后的步数就等于关于它的逆序对数。

他到最后去以后,下面的问题等价于将剩下n-1个数升序排列。

由于最大的数和后面每个数都进行了交换,所以除第n个数以外整个数列的相对的大小位置是不变的

这样就使用数学归纳法证明了上述问题的最小步数就是逆序对的个数。

Code

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define rg register
  4. #define ci const int
  5. #define cl const long long int
  6. typedef long long int ll;
  7. namespace IO {
  8. char buf[50];
  9. }
  10. template<typename T>
  11. inline void qr(T &x) {
  12. char ch=getchar(),lst=' ';
  13. while(ch>'9'||ch<'0') lst=ch,ch=getchar();
  14. while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  15. if (lst=='-') x=-x;
  16. }
  17. template<typename T>
  18. inline void write(T x,const char aft,const bool pt) {
  19. if(x<0) {putchar('-');x=-x;}
  20. int top=0;
  21. do {
  22. IO::buf[++top]=x%10+'0';
  23. x/=10;
  24. } while(x);
  25. while(top) putchar(IO::buf[top--]);
  26. if(pt) putchar(aft);
  27. }
  28. template <typename T>
  29. inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
  30. template <typename T>
  31. inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
  32. template <typename T>
  33. inline T mabs(const T a) {if(a<0) return -a;return a;}
  34. template <typename T>
  35. inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
  36. const int maxn = 100010;
  37. const int MOD = 99999997;
  38. int n;
  39. int a[maxn],b[maxn],c[maxn],d[maxn],frog[maxn],temp[maxn];
  40. ll ans;
  41. inline bool cmp1(const int &_a,const int &_b) {
  42. return a[_a]<a[_b];
  43. }
  44. inline bool cmp2(const int &_a,const int &_b) {
  45. return b[_a]<b[_b];
  46. }
  47. void ms(ci,ci);
  48. int main() {
  49. qr(n);
  50. for(rg int i=1;i<=n;++i) qr(a[i]);
  51. for(rg int i=1;i<=n;++i) qr(b[i]);
  52. for(rg int i=1;i<=n;++i) c[i]=d[i]=i;
  53. std::sort(c+1,c+1+n,cmp1);std::sort(d+1,d+1+n,cmp2);
  54. for(rg int i=1;i<=n;++i) frog[c[i]]=d[i];
  55. ms(1,n);
  56. write(ans,'\n',true);
  57. return 0;
  58. }
  59. void ms(ci l,ci r) {
  60. if(l>=r) return;
  61. int mid=(l+r)>>1;
  62. ms(l,mid);ms(mid+1,r);
  63. int i=l,j=mid+1,p=l;
  64. while((i<=mid) && (j<=r)) {
  65. if(frog[i]<frog[j]) temp[p++]=frog[i++];
  66. else temp[p++]=frog[j++],ans=(ans+mid-i+1)%MOD;
  67. }
  68. while(i<=mid) temp[p++]=frog[i++];
  69. while(j<=r) temp[p++]=frog[j++];
  70. for(i=l;i<=r;++i) frog[i]=temp[i];
  71. }

Summary

1、遇见棘手的表达式,先化简再说

2、将一个序列交换相邻元素用最小步数使得序列按照升序排列的答案就是序列中的逆序对个数

3、代码中给出了离散化的方法以及归并排序求逆序对的方法。

【逆序对相关/数学】【P1966】【NOIP2013D1T2】 火柴排队的更多相关文章

  1. 洛谷P1966 【火柴排队】

    题解 P1966 [火柴排队] 说明: 在数学中有个公式: (a1-b1)^2+(a2-b2)^2<(a2-b1)^2+(a1-b2)^2 (你可以自己试着证一下) 两列火柴对应的两根火柴在各列 ...

  2. 【题解】洛谷P1966 [NOIP2013TG] 火柴排队(树状数组+逆序对)

    次元传送门:洛谷P1966 思路 显然在两排中 每排第i小的分别对应就可取得最小值(对此不给予证明懒) 所以我们只在意两排的火柴是第几根 高度只需要用来进行排序(先把两个序列改成有序的方便离散化) 因 ...

  3. 【洛谷P1966】火柴排队

    火柴排队 题目链接 ∑(ai​−bi​)^2=∑ai^2-2*∑ai*bi+∑bi^2 显然∑ai^2+∑bi^2是不变的,我们要让 2*∑ai*bi最大,才能使原式最小 然后我们一眼就可以看出来, ...

  4. [hdu4911]逆序对相关

    思路:由于只能交换相邻的数,所以每次最多减小1个逆序对(且如果存在逆序对那么肯定可以减小1个)!于是乎..就是统计逆序对的裸题了.树状数组或归并都行. #pragma comment(linker, ...

  5. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  6. luogu P1966 火柴排队 (逆序对)

    luogu P1966 火柴排队 题目链接:https://www.luogu.org/problemnew/show/P1966 显然贪心的想,排名一样的数相减是最优的. 证明也很简单. 此处就不证 ...

  7. P1966 火柴排队——逆序对(归并,树状数组)

    P1966 火柴排队 很好的逆序对板子题: 求的是(x1-x2)*(x1-x2)的最小值: x1*x1+x2*x2-2*x1*x2 让x1*x2最大即可: 可以证明将b,c数组排序后,一一对应的状态是 ...

  8. P1966 火柴排队(逆序对)

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

  9. 洛谷P1966 火柴排队 贪心+离散化+逆序对(待补充QAQ

    正解: 贪心+离散化+逆序对 解题报告: 链接在这儿呢quq 这题其实主要难在想方法吧我觉得?学长提点了下说用贪心之后就大概明白了,感觉没有很难 但是离散化这里还是挺有趣的,因为并不是能很熟练地掌握离 ...

随机推荐

  1. 第五模块:WEB开发基础 第2章·JavaScript基础

    01-JavaScript的历史发展过程 02-js的引入方式和输出 03-命名规范和变量的声明定义 04-五种基本数据类型 05-运算符 06-字符串处理 07-数据类型转换 08-流程控制语句if ...

  2. unity实现框选效果

    思路: 在uinity中既可以将屏幕坐标转换为世界坐标,也可以将世界坐标转换为屏幕坐标.这样的话我们就可以通过判断物体在世界坐标转换为平幕坐标是否在鼠标框选的矩形区域坐标内,来判断物体是否在框选范围. ...

  3. 【sessionInfo】使用说明

    对象:sessionInfo 说明:会话类型操作,此对象是session与cookies的完善版,解决了session异常丢失及cookies文件大小的问题. 注意: 1)  访客的IP地址发生变化时 ...

  4. 交换学生 (Foreign Exchange,UVa10763)

    题目描述: 解题思路: 开一个数组,读入一次交换两个数,如果最后数组不变,即符合匹配 #include<iostream> #include<cstdio> #include& ...

  5. Python基础 之 tuple类-元组 和 dict类-字典

    tuple 元组 一.tuple 类的基本属性 1.元组,有序:元素不可被修改,不能被增加或者删除tuple类 tu = (111,22,33,44) 一般写元组的时候,推荐在最后加入,和类方法进行区 ...

  6. 【Linux 运维】linux系统修改主机名

    主机名的修改:  1.命名解释: [root@localhost~]# 分别代表: 用户名(root) 主机名(localhost) 当前路径(~,当前用户的home目录) 权限标志位(#代表root ...

  7. 关于Filter中ServletRequest强转HttpServletRequest问题

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOE ...

  8. python3 bytes与hex_string之间的转换

    1, bytes to hex_string的转换: def byte_to_hex(bins): """ Convert a byte string to it's h ...

  9. POJ 1696 Space Ant(凸包变形)

    Description The most exciting space discovery occurred at the end of the 20th century. In 1999, scie ...

  10. VS2005、VS2008中的快捷键、组合键大全

    Ctrl+E,D ----格式化全部代码 Ctrl+E,F ----格式化选中的代码 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL ...