[POI 2009] SLO-Elephants

这道题给了两个全排列 \(a,b\)
给了交换每个数的权值。
求通过交换使 \(a\)\(b\) 完全相同的最小总权值。
可以发现 \(a\)\(b\) 中相同下标的数之间可以构成一个环。
而很容易想到环内的交换肯定是较优的。
由于每个数必然被交换一次,那么和它交换的数越小代价就越小。
所以对于环内的交换可以每次都用最小的数去换。
总代价为 \(sum+mi*(len-2)\)
接着还可以想到如果环内的数的权值都过大,这时可以使用环外的最小值来代替最小值进行交换。
总代价为 \(sum+mi+ami*(len+1)\), \(ami\) 为全局最小值。
这样对于每个环都计算一遍累计出总答案。
代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,w[1000001],a[1000001],b[1000001],to[1000001],pos[1000001];
bool vis[1000001];
int ami=0x3f3f3f3f,ans;
signed main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i],ami=min(ami,w[i]);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++)pos[b[i]]=i;
    for(int i=1;i<=n;i++)to[i]=pos[a[i]];
    for(int i=1;i<=n;i++){
        if(vis[i])continue;
        int j=i,k=0,sum=0,mi=0x3f3f3f3f;
        do{vis[j]=1,k++,sum+=w[a[j]],mi=min(mi,w[a[j]]),j=to[j];}while(j!=i);
        if(k==1)continue;
        int s1=sum+mi*(k-2),s2=sum+mi+ami*(k+1);
        ans+=min(s1,s2);
    }
    cout<<ans;
    return 0;
}
posted @ 2025-08-18 10:47  zhuoheng  阅读(9)  评论(0)    收藏  举报