火柴排队
题目链接: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;
}

浙公网安备 33010602011771号