码迷,mamicode.com
首页 > 其他好文 > 详细

NOIp2013 火柴排队

时间:2018-05-06 22:17:31      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:定义   顺序   void   har   uniq   stream   org   逆序对数   一个   

Luogu

其实只用交换一列火柴就行了

我们用一种套路求出来怎样才是最优的高度

不难得知,当第一列火柴以最优的结果排列,再怎么交换都不会使答案更优

也就是 \((a_i-b_i)^2+(a_{i+1}-b_{i+1})^2<(a_{i+1}-b_i)^2+(a_i-b_{i+1})^2\)

整理得到 \(a_ib_i+a_{i+1}b_{i+1}>a_ib_{i+1}+a_{i+1}b_i\)

充分发挥人类智慧,就可以发现当 \(a_i<a_{i+1},b_i<b_{i+1}\) 时答案最优

又因为对 \(i\) 位置答案有贡献的只有 \(a_i,b_i\) 所以当 \(a,b\) 的排列顺序一样时也是最优的

\(a,b\) 都离散化一下,就只要将 \(a\) 移移移成 \(b\) 就行了。

那不就是相当于重新定义了大小的逆序对吗?

再把 \(a\)\(b\) 来手玩一下新的大小,求一下逆序对数就是答案了。

下面将蒯过来某dalao对于"为什么最少交换次数是逆序对数"这个问题的解答

1.如果这个序列不存在最小逆序对,那么这个序列有序(即逆序对为0),用反证法证明就是如果有两个不相邻的逆序元素那么中间的元素会里外不是人,所以这个序列必须有序

2.每次交换两个相邻元素,逆序对只变动1,证明就是,如果有别的元素和这两个的逆序关系发生了也发生了变化可以通过分情况讨论证明这种情况不存在

那么我们将这个序列排序的手段就是不停的交换两个最小逆序对,每次逆序对变动1所以最后排序的总数一定是逆序对数

其他方案一定在某一步中交换了一个顺序对,这会导致逆序对的个数增加,一定不优,证明完毕……
#include <iostream>
#include <cstdio>
#include <algorithm>

const int MaxN = 1e5 + 5;
const int Mod = 99999997;

int N, Tot, Ans;
int A[MaxN], B[MaxN], C[MaxN];

inline int read()
{
    register int x = 0;
    register char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch))
    {
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x;
}

void merge_sort(int l, int r)
{
    if(l == r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);
    for(int i = l, l1 = l, l2 = mid + 1; i <= r; ++i)
    {
        if((A[l1] < A[l2] && l1 <= mid ) || l2 > r) C[i] = A[l1++];
        else
        {
            (Ans += (mid - l1 + 1)) %= Mod;
            C[i] = A[l2++];
        }
    }
    for(int i = l; i <= r; ++i) A[i] = C[i];
}

int main()
{
    N = read();
    for(int i = 1; i <= N; ++i) A[i] = read();
    for(int i = 1; i <= N; ++i) B[i] = read();
    for(int i = 1; i <= N; ++i) C[i] = A[i];
    std::sort(&C[1], &C[N + 1]);
    Tot = std::unique(&C[1], &C[N + 1]) - &C[1];
    for(int i = 1; i <= N; ++i) A[i] = std::lower_bound(&C[1], &C[Tot + 1], A[i]) - &C[0];
    for(int i = 1; i <= N; ++i) C[i] = B[i];
    std::sort(&C[1], &C[N + 1]);
    Tot = std::unique(&C[1], &C[N + 1]) - &C[1];
    for(int i = 1; i <= N; ++i) B[i] = std::lower_bound(&C[1], &C[Tot + 1], B[i]) - &C[0];
    for(int i = 1; i <= N; ++i) C[B[i]] = i;
    for(int i = 1; i <= N; ++i) A[i] = C[A[i]];
    merge_sort(1, N);
    printf("%d\n", Ans);
    return 0;
}

NOIp2013 火柴排队

标签:定义   顺序   void   har   uniq   stream   org   逆序对数   一个   

原文地址:https://www.cnblogs.com/zcdhj/p/8999751.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!