【POI 12】【Double-row】

来源:互联网 发布:在哪里买域名比较好 编辑:程序博客网 时间:2024/06/14 13:04

题目大意

有两个序列,可以调换两个序列相应的位置的元素,求最少步骤使得每个序列所含元素互不相同。

解题思路

可以发现一个元素最多出现两次,必须在不同序列,所以我们可以枚举一个元素的状态,便可以确定一个连通块的状态。注意有多个连通块,它们相互独立。

code

//#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define LL long long#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)using namespace std;int const maxn=50000,maxx=100000,inf=2147483647;int n,gra,to[maxn*2+10],next[maxn*2+10],begin[maxn+10],a[maxn+10],b[maxn+10],c[maxx+10][10],    queue[maxn+10],tag[maxn+10];bool visit[maxn+10],done[maxn+10];void insert(int u,int v){    if(u==v)return;    to[++gra]=v;    next[gra]=begin[u];    begin[u]=gra;}int coun(int t,int u,int v){    int re;    if(t)swap(a[u],b[u]);    if((a[u]==a[v])||(b[u]==b[v]))re=1;else re=0;    if(t)swap(a[u],b[u]);    return re;}int bfs(int u,int v){    int head=0,tail=0,sum=v;    visit[queue[++tail]=u]=1;    tag[u]=v;    for(;head!=tail;){        int now=queue[++head];        for(int i=begin[now];i;i=next[i])            if(!visit[to[i]]){                sum+=(tag[to[i]]=coun(tag[now],now,to[i]));                visit[queue[++tail]=to[i]]=1;            }else if(tag[to[i]]!=coun(tag[now],now,to[i]))return inf;    }    fo(i,1,tail)done[queue[i]]=1,visit[queue[i]]=0;    return sum;}int main(){    freopen("d.in","r",stdin);    freopen("d.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)scanf("%d",&a[i]),c[a[i]][++c[a[i]][0]]=i;    fo(i,1,n)scanf("%d",&b[i]),c[b[i]][++c[b[i]][0]]=i;    fo(i,1,maxx)if(c[i][0]>1)insert(c[i][1],c[i][2]),insert(c[i][2],c[i][1]);    int ans=0;    fo(i,1,n)        if(!done[i])            ans+=min(bfs(i,0),bfs(i,1));    printf("%d",ans);    return 0;}
0 0
原创粉丝点击