Gym CERC 16 F Free Figuriness 思维+模拟

来源:互联网 发布:中国房地产库存数据 编辑:程序博客网 时间:2024/05/16 17:22
CERC 16
Problem F
题意:给出序列a和目标序列b.下标小的可以放到下标大的内部.每个物品内部最多直接放一个物品.a[i]!=0 则表示i放在a[i]内部.
操作1:x放入y  (条件:节点y是空的(y无父节点也没前驱) && x没有父节点.)
操作2 把x从y中取出 (条件:节点y父节点.)
问将序列a变为序列b的最小操作次数? n<=1e5.


n=6 a={2,5,4,0,0,0},b={2,6,4,5,0,0};
a的嵌套方式:{1->2->5},{3->4}.
b的嵌套方式:{1->2->6},{3->4->5}.
3次操作:连接2->6 删除2->5 连接4->5.




若a[i]!=b[i] 则要想让i指向b[i] 
只能先把i->a[i]->..这条链全部拆掉.


b[i]不能有直接的儿子 x->b[i]
x->b[i]已经在第一步被删除了 (第一步后i->b[i] 或者i->'0')


然后b[i]要为free b[i]->nxt->..这条链也只能全部拆掉.

现在a[i]!=b[i]的 可以直接把i->b[i]即可 (i and b[i] are free && b[i] has no son)

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=1e5+5;int n,a[N],b[N],vis[N],p[N];int main(){    while(cin>>n)    {        int ans=0;        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        for(int i=1;i<=n;i++)            scanf("%d",&b[i]);        for(int i=1;i<=n;i++)            p[a[i]]=i;        for(int i=1;i<=n;i++)        {            if(a[i]==b[i])  continue;            //i->a[i]->.. destroy            int y;            for(int x=i;a[x];x=y)            {                y=a[x];                a[x]=0,p[y]=0;                ans++;            }        }        //i->b[i] or i->'0'         //do:i->b[i]:only if b[i] is free (right now b[i] has no son)        for(int i=1;i<=n;i++)        {            if(a[i]==b[i])  continue;            //b[i]->nxt->.. destroy            int y;            for(int x=b[i];a[x];x=y)            {                y=a[x];                a[x]=0,p[y]=0;                ans++;            }        }        for(int i=1;i<=n;i++)            if(a[i]!=b[i]) // i and b[i] are free now                ans++;        cout<<ans<<endl;    }    return 0;}

7
3 5 4 0 7 0 0
3 5 0 6 7 0 0
原创粉丝点击