【NOIP2013提高组】火柴排队

https://www.luogu.org/problem/show?pid=1966

Σ(ai-bi)2=Σai2+Σbi2-2Σai*bi,要使Σ(ai-bi)2最小,则需2Σai*bi最大。

由排序不等式可知两列数字里第一大与第一大对应,第二大与第二大对应,……,第k大与第k大对应,……,第n大与第n大对应时,Σai*bi最大。

故先将第一列每个数字映射到第二列排名相同的数字,再求需要交换的次数,也就是逆序对的个数。

#include <algorithm>
#include <iostream>
#include <vector>
#define maxn 100005
typedef long long llint;
using namespace std;
int n;
llint tmp[maxn], sorted[maxn], cnt = 0;
void merge_sort(int l, int r)
{
    if (l == r)
        return;

    int mid = (l + r) / 2;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);

    int p1 = l, p2 = mid + 1, p = l;
    while (p1 <= mid && p2 <= r)
    {
        if (sorted[p1] <= sorted[p2])
            tmp[p++] = sorted[p1++];
        else
        {
            cnt = (cnt + (mid - p1 + 1)) % 99999997;
            tmp[p++] = sorted[p2++];
        }
    }

    while (p1 <= mid)
        tmp[p++] = sorted[p1++];
    while (p2 <= r)
        tmp[p++] = sorted[p2++];

    for (int i = l; i <= r; i++)
        sorted[i] = tmp[i];
}
template <class T> void print(T *p)
{
    for (int i = 1; i <= n; i++)
        cout << p[i] << ‘ ‘;
    cout << endl;
}
pair<llint, llint> a[maxn], b[maxn];
int rnk[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].first;
        a[i].second = i;
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i].first;
        b[i].second = i;
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);

    for (int i = 1; i <= n; i++)
        sorted[a[i].second] = b[i].second; // 将第一列排第i名的项与第二列排第i名的项对应
    merge_sort(1, n);
    cout << cnt << endl;
    return 0;
}
时间: 2024-12-04 12:18:33

【NOIP2013提高组】火柴排队的相关文章

NOIP2013提高组DAY1T2火柴排队 vijos1842

火柴排队 描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑i=1n(ai−bi)2,其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度. 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小.请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果. 格式 输入格

【解题】noip2013提高组(day1+day2)

这套题,勾起了我无数美好的回忆←意思是该好好复习了... [day1] 一.转圈游戏 首先,第一题,在处理k的时候应该用快速幂算法. 大概就是下面这样,要注意的是:1.二分时要判断有无余数.2.先设数,在进行乘积运算,不然会递归两次=.= 1 int pow(int a,int pos) 2 { 3 if(pos==1) return a%t; 4 int temp=pow(a,pos/2); 5 if(pos%2==1) return (temp*temp*a)%t; 6 return (te

noip2013 提高组

T1 转圈游戏 题目传送门 果不其然 第一题还是模拟题 一波快速幂解决问题 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c&

NOIP2013提高组 T2 火柴排队

一开始看也想不到这居然要用到逆序对,归并排序. 先来看看题目: 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度. 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小.请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对

火柴排队——noip2013——提高组

作为D1T2的这题,做法的确挺巧妙的. 首先,我们发现: 对于a1<a2,   b1>b2 则  (a1-b1)^2+(a2-b2)^2>(a1-b2)^2+(a2-b1)^2 自己拆开推一下就知道了.. 然后我们对数据进行离散化.把b数组的元素映射到a里. 由于我们需要求,使映射完的结果不下降,需要调换多少次. 求这个,也就可以转换成求逆序对. 然后,就大功告成了. #include<iostream> #include<cstdio> #include<

2016.7.12 NOIP2013提高组 day2解题报告(未完成版)

考试马不停蹄地到来,昨天的程序还没改完,今天又考了day2,虽然没有昨天那么懵逼,但还是不尽如人意,现在还没讲题,我打算先自己看一次解题报告,争取加深理解,毕竟一位前辈说过,做一套题的质量取决于题本身的质量和你思考的程度. 考试总结: 1.数据分析推测可行算法很重要,要灵活掌握常用算法的时间复杂度: 2.对拍的方式要熟练,写对拍耗费的时间过多: 3.要加强代码实现的能力,比较突出的表现就是写200-300行多函数模拟或搜索的能力: 4.不要急于写过不完的程序,要多拿一点时间来分析数据,样例不够还

洛谷 P1969 积木大赛(NOIp2013提高组D2T1)

题目描述 春春幼儿园举办了一年一度的"积木大赛".今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成n块高度为 0 的积木).接下来每次操作,小朋友们可以选择一段连续区间[l, r],然后将第第 L 块到第 R 块之间(含第 L 块和第 R 块)所有积木的高度分别增加1. 小 M 是个聪明的小朋友,她很快想出了建造大厦的最佳策略,使得建造所需的操作次数最少.但她不是一个勤于动手的孩子,所

[部分题解]noip2013提高组Day2

积木大赛: 之前没有仔细地想,然后就直接暴力一点(骗点分),去扫每一高度,连到一起的个数,于是2组超时 先把暴力程序贴上来(可以当对拍机) 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 FILE *fin = fopen("block.in","r"); 5 FILE *fout= fopen("block.out","w&quo

noip2013——提高组——积木大赛

noip2013 D2T1 太简单了,不说了. #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int read(){ int t=1,num=0; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>=