题解 P3482 【[POI2009]SLO-Elephants】
pythoner713 · · 题解
将数组
发现可以组成三个“环”:
这些环互不影响,可以逐个击破。
对于长度为
按照上述策略还原一个环的代价是:
这里的
对于每个环无非就是上述两种策略,取代价小者加起来即可。
#include<bits/stdc++.h>
#define int long long
#define nb 1000010
using namespace std;
int n, ans, min2 = 2e9, a[nb], b[nb], A[nb], w[nb];
bool vis[nb];
void work(int x){
int len = 0, sum = 0, min1 = 2e9;
while(!vis[x]){
vis[x] = 1; // 标记当前环内的数
sum += w[a[x]]; // 累加当前环代价和
min1 = min(min1, w[a[x]]); // 找出环内最小代价
x = A[b[x]]; // 跳至环内下一个数
len++; // 统计当前环的长度
}
int p = sum + min1 * (len - 2); // 策略一
int q = sum + min1 + min2 * (len + 1); // 策略二
ans += min(p, q);
}
signed main(){
cin >> n;
ios::sync_with_stdio(0);
for(int i = 1; i <= n; i++) cin >> w[i], min2 = min(min2, w[i]);
for(int i = 1; i <= n; i++) cin >> a[i], A[a[i]] = i; // 将值映射到 a 的下标
for(int i = 1; i <= n; i++) cin >> b[i];
for(int i = 1; i <= n; i++) if(!vis[i]) work(i); // 找到新环,逐个击破
cout << ans;
return 0;
}
最后顺便提一提,对于数组内交换的题,拆分成环考虑是常见的套路。可以顺便看看这两题: