明年要是考这种我就得回家种地去了= =
题意比较简单就不说了。
表示从来没做过这种题目,n脸懵比。。。
看了neither_nordalao的题解,思考了一下大概明白了。
拿样例举个例子:
1 4 5 3 6 2
5 3 2 4 6 1
我们可以发现这中间有3个循环节(1,5,2)(3,4)(6)
循环节的定义就是每一个循环节内的数字之间交换一定次数后还会回归到原来的状态= =
那么明显我们通过将a映射到b里,找出所有的循环节,然后就可以计算答案。
加入我们只对每个循环节内进行数字交换,那么设mn表示交换一个所需的最小代价,l为循环节长度,那么明显我们要交换2*(l-1)次,除了l个数字固定所以代价固定,其余l-2次每一次的交换都通过mn来交换是最优的,那么明显有ans+=sum+mn*(l-2)
但是这样不一定是最优的,所以我们还可以将其他循环节内(整个序列内)最小的那个拉过来交换,两种方案取个min就好了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e6+5;
typedef long long ll;
ll ans;
int n,m;
ll w[N],minn=1e15;
int a[N],p[N],b[N],vis[N];
int main()
{
scanf("%d",&n);
fo(i,1,n)scanf("%d",&w[i]),minn=min(minn,w[i]);
fo(i,1,n)
{
scanf("%d",&a[i]);
p[a[i]]=i;
}
fo(i,1,n)scanf("%d",&b[i]);
ans=0;
fo(i,1,n)
if (!vis[i]&&a[i]!=b[i])
{
int x=i;
int siz=0;
ll sum=0;
int mn=1e9;
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+1ll*mn*(siz-2),sum+mn+1ll*minn*(siz+1));
}
printf("%lld\n",ans);
return 0;
}