luogu1966 火柴排队
题目大意
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为: $\sum_{i=1}^n(a_i-b_i)^2$,其中 ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第 i 个火柴的高度。 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
题解
预备知识
- 因为任何a火柴的交换效果都与b交换火柴相同,所以我们只让b火柴移动。
- 通过邻项交换的方法,我们可以得到一个序列的任意一个排列。
贪心
我们让序列$b$序列变换后的结果序列称为$b'$。那么对$\forall i$,$a_i$在$a$中的大小排名与$b'_i$在$b'$中的相同。
证明为邻项交换。如果$a_1$与$b_1$配对,$a_2$与$b_2$配对,$a_1\leq a_2, b_1 \leq b_2$,则这样得到的结果,比$a_1$和$b_2$、$a_2$和$b_1$配对得到的结果小。为了表示方便,我们令$x=a_1,y=b_1,a_2=x+k,b_2=y+t$,则前者的结果为$$(x-y)^2+(x+k-b-t)^2$$,后者结果为$$(a-b-t)^2+(a+k-b)^2$$。后者减去前者得到的结果为$$2kt$$,恒大于0。故原命题成立。
如何得到$b'$?
$b'$的要求是如果将$a$排序的变换为$f(a)$,则$f(b')$得到的序列也是递增的。也就是说,我们要得到$b'$,要先将$b$排序得到$b''$,随后$f^{-1}(b'')=b'$。那么达到$f^{-1}$的方法便是将$a$排序后的rank为下标,原来的id为值得到一个数组,随后将每个$b''$移到对应的id位置去即可。
那么要交换多少次呢?
即为逆序对数。用树状数组解决即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define ll long long
const int MAX_N = 100010;
const ll P = 99999997;
int N;
int NewId_OrgId[MAX_N]; struct BIT
{
private:
ll C[MAX_N]; int Lowbit(int x)
{
return x & -x;
} public:
void Update(int p, ll delta)
{
while (p <= N)
{
C[p] += delta;
p += Lowbit(p);
}
} ll Query(int p)
{
ll ans = 0;
while (p > 0)
{
ans += C[p];
p -= Lowbit(p);
}
return ans;
}
}g; struct Node
{
int Id, Val; bool operator < (const Node &a) const
{
return Val < a.Val;
}
}A[MAX_N], B[MAX_N], B1[MAX_N]; int main()
{
scanf("%d", &N);
for (int i = 1; i <= N; i++)
A[i].Id = B[i].Id = i;
for (int i = 1; i <= N; i++)
scanf("%d", &A[i].Val);
for (int i = 1; i <= N; i++)
scanf("%d", &B[i].Val);
sort(A + 1, A + N + 1);
for (int i = 1; i <= N; i++)
NewId_OrgId[i] = A[i].Id;
sort(B + 1, B + N + 1);
for (int i = 1; i <= N; i++)
B1[NewId_OrgId[i]] = B[i];
ll ans = 0;
for (int i = N; i >= 1; i--)
{
ans = (ans + g.Query(B1[i].Id - 1)) % P;
g.Update(B1[i].Id, 1);
}
printf("%lld\n", ans);
return 0;
}
luogu1966 火柴排队的更多相关文章
- luogu1966 火柴排队(离散化+树状数组)
由于是一个二次函数的关系,所以易证应该尽量让两组的顺序相同 然后就离散化乱搞几发,最后就变成了求逆序对的数量了 #include<bits/stdc++.h> #define pa pai ...
- $Noip2013/Luogu1966$ 火柴排队 贪心+离散化+逆序对
$Luogu$ $Description$ 给定等长的$a,b$两个序列.每次可以交换一个序列中相邻两个数.求最小的交换次数使得$\sum(a_i-b_i)^2$最小. $Sol$ 交换后的序列一定满 ...
- Codevs 3286 火柴排队 2013年NOIP全国联赛提高组 树状数组,逆序对
题目:http://codevs.cn/problem/3286/ 3286 火柴排队 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : ...
- 洛谷P1966 【火柴排队】
题解 P1966 [火柴排队] 说明: 在数学中有个公式: (a1-b1)^2+(a2-b2)^2<(a2-b1)^2+(a1-b2)^2 (你可以自己试着证一下) 两列火柴对应的两根火柴在各列 ...
- [树状数组+逆序对][NOIP2013]火柴排队
火柴排队 题目描述 涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑ (ai-bi)2,i=1,2,3,. ...
- 【刷题】洛谷 P1966 火柴排队
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
[NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...
- LOJ2609. NOIP2013 火柴排队 【树状数组】
LOJ2609. NOIP2013 火柴排队 LINK 题目大意: 给你两个数列,定义权值∑i=1(ai−bi)^2 问最少的操作次数,最小化权值 首先需要发现几个性质 最小权值满足任意i,j不存在a ...
- 洛谷 P1966 火柴排队 解题报告
P1966 火柴排队 题目描述 涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: \(\s ...
随机推荐
- Chrome插件:浏览器后台与页面间通信
content.js 与 background.js和popup.js 通信和 background.js与popup.js 这些通信都用 chrome.runtime.sendMessage 这个 ...
- Linux从入门到适应(三):Ubuntu16.04将python从3.5升级到3.6
1 将python从默认的python2.7更换为python3.5 : sudo update-alternatives --install /usr/bin/python python /usr/ ...
- Java核心技术卷1 第三章
1. Java区分大小写,下一段源代码中,关键字public称为访问修饰符,用于控制程序的其他部分对于这段代码的访问级别,关键字class表明Java程序中的全部内容都包含在类里面. 标准的类名命名规 ...
- Java中Date类型的工具类
package com.mytripod.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import ja ...
- PHP实现QQ第三方登录的方法
前言: PHP实现QQ快速登录,罗列了三种方法 方法一:面向过程,回调地址和首次触发登录写到了一个方法页面[因为有了if做判断], 方法二,三:面向对象 1.先调用登录方法,向腾讯发送请求,2.腾讯携 ...
- python3.6的requests库&HTMLTestRunner实现测试报告
'''1. 在suite.addTest时,可以把需要的用例先写入一个列表list中,list当做addTest的参数:2. 在unittest.main(verbosity=2)中,默认为1,设置为 ...
- 全国高校json数据包(复python解析代码)
由于这段时间需要有关学校的三级联动插件,找了很久没有找到合适的,所以去教育部官网下载了一份全国普通高校名单(2019年), 这里附上解析该xls文件的代码 import xlrd import jso ...
- 洛谷 4933 洛谷10月月赛II T2 大师
[题解] f[i][j]表示最后一个数为h[i],公差为j的等差数列的个数.n方枚举最后一个数和倒数第二个数转移即可.注意公差可能为负数,需要移动为正数再作为下标. #include<cstdi ...
- get方法和set方法
定义一个类,该类有一个私有成员变量,通过构造方法将其进行赋初值,并提供该成员的getXXX()和setXXX()方法 提示:假设有private String name;则有 public void ...
- 567. Permutation in String
Problem statement: Given two strings s1 and s2, write a function to return true if s2 contains the p ...