您的位置:首页 > 其它

bzoj 1119: [POI2009]SLO(置换)

2016-05-21 08:57 381 查看

1119: [POI2009]SLO

Time Limit: 30 Sec Memory Limit: 162 MB

Submit: 557 Solved: 268

[Submit][Status][Discuss]

Description

对于一个1-N的排列(ai),每次你可以交换两个数ax与ay(x<>y),代价为W(ax)+W(ay) 若干次交换的代价为每次交换的代价之和。请问将(ai)变为(bi)所需的最小代价是多少。

Input

第一行N。第二行N个数表示wi。第三行N个数表示ai。第四行N个数表示bi。 2<=n<=1000000 100<=wi<=6500 1<=ai,bi<=n ai各不相等,bi各不相等 (ai)<>(bi) 样例中依次交换数字(2,5)(3,4)(1,5)

Output

一个数,最小代价。

Sample Input

6

2400 2000 1200 2400 1600 4000

1 4 5 3 6 2

5 3 2 4 6 1

Sample Output

11200

HINT

感谢MT大牛贡献译文.

Source



[Submit][Status][Discuss]


HOME Back

题解:置换。

这道题与poj 3270很相似,都牵扯到了轮换,对于一组轮换你总可以通过从中选取最小的数,用最小的数与其他数交换K-1次的方式使当前的轮换达到目标状态。

观察样例可以发现

1 4 5 3 6 2

5 3 2 4 6 1

样例中有三个轮换(5,2,1)(4,3)(6) 这里只的是数不是位置,当然如果改成位置的话就是(1,3,6)(2,4)
(5)。然后像poj 3270 那样搞就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000003
#define LL long long
using namespace std;
int n,m;
LL w
,minn;
int a
,cnt
,b
,use
;
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
minn=1000000000;
for (int i=1;i<=n;i++)  scanf("%lld",&w[i]),minn=min(minn,w[i]);
for (int i=1;i<=n;i++)  scanf("%d",&a[i]);
for (int i=1;i<=n;i++){
int x; scanf("%d",&x);
cnt[x]=i;
}
LL ans=0;
for (int i=1;i<=n;i++)
if (!use[i]){
int j=i; LL mnow=1000000000; LL len=0;
LL sum=0;
while (!use[j]){
len++;
mnow=min(mnow,w[a[j]]);
sum+=w[a[j]];
use[j]=1;
j=cnt[a[j]];
}
if (len==1)  continue;
LL t1=sum+(LL)(len-2)*mnow;
LL t2=sum+mnow+(LL)(len+1)*minn;
ans+=min(t1,t2);
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: