火柴排队

题目链接:https://www.luogu.com.cn/record/215601289

题意:

给定两个数列,规定S=(ai-bi)^2(1<=i<=n)求和

为了使S最小,求移动bi的最小次数(每次移动可交换相邻两个数)

思路:

首先发现S=ai2+bi2 - 2xaixbi

前两项无法改变,只能使第三项尽可能大

那么观察发现ai与bi越接近,它们的乘积越大

容易证明对于离散化后的两个数组,它们的大小编号一一对应时,即为S最小时的情况

然而我们需要移动b数组

如果b离散化后:3 4 2 1

a离散化后:2 1 3 4

那么b->a,b每一个位置上要 移动到的 位置数组:3 4 1 2

由于移动是双向的,所以位置数组大的元素移动到右边时,小的元素也会相应的移动到左边

所以只需要统计大的数所需要移动的步数即可

即求数组的逆序对

可以用树状数组/归并求

int mn;
int lowbit(int x){
  return x&-x;
}
int t[maxn];
void add(int x){
    while(x<=mn){
      t[x]++;
      x+=lowbit(x);
    }
}
int query(int x){
  int res=0;
  while(x){
    res+=t[x];
    x-=lowbit(x);
  }
  return res;
}

void solve(){
    int n;cin>>n;
    mn=n;
    vector<pii>a(n+1);
    vector<pii>b(n+1);
    rep(i,1,n){
      cin>>a[i].fi;
      a[i].se=i;
    }
    rep(i,1,n){
       cin>>b[i].fi;
      b[i].se=i;
    }
    sort(a.begin()+1,a.end());
    sort(b.begin()+1,b.end());
    vector<int>x(n+1);
    vector<int>y(n+1);
    rep(i,1,n){
        x[a[i].se]=i;
        y[b[i].se]=i;
    }
    map<int,int>mp;
    rep(i,1,n){
      mp[x[i]]=i;
    }
    vector<int>res(n+1);
    rep(i,1,n){
      res[i]=mp[y[i]];
    }

    int ans=0;
    for(int i=1;i<=n;i++){
      add(res[i]);
      ans+=i-query(res[i]);
      ans%=mod;
    }
    cout<<ans<<endl;
}
posted @ 2025-05-01 17:32  Marinaco  阅读(16)  评论(0)    收藏  举报
//雪花飘落效果