1. 程式人生 > >[NOIP2013] 火柴排隊

[NOIP2013] 火柴排隊

歸並 元素 構造 namespace ++ names ans getc pan

[題目鏈接]

https://loj.ac/problem/2609

[算法]

首先將式子化簡 :

sigma( (ai - bi) ^ 2) = sigma( ai^2 + bi^2 - 2aibi )

顯然 , 只需最大化aibi就能最小化“距離”

考慮貪心 , 將a中最小元素與b中最小元素組合 , a中第二小與b中第二小組合 ... , 不難證明這樣是最優的 ,

因為 : 設a < b , c < d , 將a與c組合 , b與d組合比a與d組合 , b與c組合更優。

不妨先將a和b升序排序 ,記錄每個元素的初始位置 , 構造新序列p, 令p[a[i].id] = b[i].id , 問題就轉化為了 , 每次可以交換相鄰兩個元素 , 要求用最少的次數時p按升序排列。

只需求出逆序對數即可。 可以用歸並排序或樹狀數組實現 , 筆者使用的是樹狀數組

[代碼]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
const int P = 99999997;

struct info
{
        int value;
        int id;
} a[MAXN],b[MAXN];

int n,ans;
int c[MAXN];

template <typename T> inline void read(T &x)
{
    
int f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 0; x *= f; } struct Binary_Indexed_Tree { int c[MAXN]; inline int lowbit(int x) {
return x & (-x); } inline void modify(int pos,int val) { for (int i = pos; i <= n; i += lowbit(i)) c[i] = (c[i] + val) % P; } inline int query(int pos) { int ret = 0; for (int i = pos; i; i -= lowbit(i)) ret = (ret + c[i]) % P; return ret; } } BIT; inline bool cmp(info a,info b) { return a.value < b.value; } int main() { read(n); for (int i = 1; i <= n; i++) { read(a[i].value); a[i].id = i; } for (int i = 1; i <= n; i++) { read(b[i].value); b[i].id = 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].id] = b[i].id; for (int i = 1; i <= n; i++) { ans = (ans + (i - BIT.query(c[i] - 1) - 1) % P + P) % P; BIT.modify(c[i],1); } printf("%d\n",ans); return 0; }

[NOIP2013] 火柴排隊