[NOIP2013] 火柴排隊
阿新 • • 發佈:2018-09-03
歸並 元素 構造 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] 火柴排隊