[luogu]P1966 火柴排队(离散,逆序对)

题目

每盒装有n根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为\sum (a_i-b_i)^2∑(ai​−bi​)2

其中a_{i} 表示第一列火柴中第ii个火柴的高度,b_{i}表示第二列火柴中第 i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997取模的结果。

分析

由于交换a,b两个序列可以等价于只交换一个序列,故只考虑交换b序列

对于特定的两组(a_{i},b_{i}),(a_{j},b_{j}),不妨a_{i} \leq a_{j},tot_{ij}=(a_{i}-b_{i})^{2}+(a_{j}-b_{j})^{2},若交换i,j,则tot_{ji}=(a_{i}-b_{j})^{2}+(a_{j}-b_{i})^{2},

\\ tot_{ji}-tot_{ij}=2(-a_{i}b_{j}+a_{j}b_{i}+a_{i}b_{i}+a_{j}b_{j})=2(a_{i}-a_{j})(b_{i}-b_{j}),可知若要使总和最小需b_{i} \leq b_{j}.对于整体,即交换后a序列每个元素的排名与b序列对应元素排名相同.

故先离散,再求逆序对即为答案(可以通过归并或树状数组求解)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

using LL = long long;
const int MAXN = 1e6 + 5;
const int MOD = 99999997;
int N;
struct node {
  LL v, id, rank, newid;
} A[MAXN], B[MAXN];
int hashx[MAXN];
bool cmp1(node, node);
bool cmp2(node, node);
LL ans;
LL p[MAXN];
void MergeSort(int, int);
int bit[MAXN];
void add(int pos, int key);
int query(int pos);

int main(){
  ios::sync_with_stdio(false);
  int i;
  cin >> N;
  for(i = 1; i <= N; i++) cin >> A[i].v, A[i].id = i;
  for(i = 1; i <= N; i++) cin >> B[i].v, B[i].id = i;
  sort(A + 1, A + 1 + N, cmp1);
  for(i = 1; i <= N; i++) hashx[i] = A[i].id;
  sort(B + 1, B + 1 + N, cmp1);
  for(i = 1; i <= N; i++) B[i].newid = hashx[i];
  sort(B + 1, B + 1 + N, cmp2);
  for(i = 1; i <= N; i++) p[i] = B[i].newid;
  //MergeSort(1, N);
  for(i = N; i >= 1; i--){
    ans += query(p[i]), ans %= MOD;
    add(p[i], 1);
  }
  cout << ans << endl;
  return 0;
}

void Merge(int l, int mid, int r);
void MergeSort(int l, int r){
  if(l < r){
    int mid = (l + r) >> 1;
    MergeSort(l, mid);
    MergeSort(mid + 1, r);
    Merge(l, mid, r);
  }
}

LL L[MAXN], R[MAXN];
void Merge(int l, int mid, int r){
  int i, j, k;
  for(i = l; i <= mid; i++) L[i] = p[i];
  for(j = mid + 1; j <= r; j++) R[j] = p[j];
  L[i] = R[j] = MAXN;
  i = l, j = mid + 1, k = l;
  while(k <= r){
    if(L[i] < R[j])
      p[k] = L[i++];
    else{
      p[k] = R[j++];
      ans += (mid - i + 1), ans %= MOD;
    }
    k++;
  }
}

#define lowbit(x) (x & (-x))
void add(int pos, int key){
  while(pos <= N){
    bit[pos] += key;
    pos += lowbit(pos);
  }
}

int query(int pos){
  int res = 0;
  while(pos){
    res += bit[pos];
    pos -= lowbit(pos);
  }
  return res;
}

bool cmp1(node x, node y){
  return x.v < y.v || (x.v == y.v && x.id < y.id);
}

bool cmp2(node x, node y){
  return x.id < y.id;
}

猜你喜欢

转载自blog.csdn.net/Hardict/article/details/82631058
今日推荐