BZOJ1119 [POI2009]SLO

来源:互联网 发布:人工智能失控 编辑:程序博客网 时间:2024/04/28 16:18

一看题就一副置换群的样子……找到循环节,然后假设循环节长度为l,那么如果只在循环节内交换的话,一定每个数至少被计入代价一次,且一共要有2*(l-1)个数被计入答案,显然除了每个数至少一次外剩下的那l-2次都让最小的被计入答案最优

但是这样对于这个循环节有可能不是最优,我们可以强行把一个不在循环节里的数拉进来,那么我们肯定要让所有数里最小的和循环节里最小的交换,把所有数里最小的拉进来,然后让所有数里最小的那个被计入答案l-2次,然后再把这个数和循环节内最小的换回来

对每个循环节把这两种方法取min,加到答案里即可

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<iomanip>#include<vector>#include<map>#include<set>#include<bitset>#include<queue>#include<stack>using namespace std;#define MAXN 1000010#define MAXM 1010#define INF 1000000000#define MOD 1000000007#define eps 1e-8#define ll long longint n;int a[MAXN],b[MAXN],w[MAXN];int p[MAXN];bool vis[MAXN];ll ans;int MN=INF;int main(){int i;scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d",&w[i]);MN=min(MN,w[i]);}for(i=1;i<=n;i++){scanf("%d",&a[i]);p[a[i]]=i;}for(i=1;i<=n;i++){scanf("%d",&b[i]);}for(i=1;i<=n;i++){if(!vis[i]&&a[i]!=b[i]){int x=i;int mn=INF;int siz=0;ll sum=0;while(!vis[x]){vis[x]=1;sum+=w[a[x]];siz++;if(w[a[x]]<=mn){mn=w[a[x]];}x=p[b[x]];}ans+=min(sum+(ll)mn*(siz-2),sum+mn+(ll)MN*(siz+1));}}printf("%lld\n",ans);return 0;}/**/


0 0