1. 程式人生 > >【2018 計蒜之道 複賽】計蒜客 貝殼找房魔法師顧問

【2018 計蒜之道 複賽】計蒜客 貝殼找房魔法師顧問

需要注意的問題是修改是可以傳遞的,也就是如果1能改成22能改成3,那麼1就能改成3
如果兩個串都是可修改的比較簡單,只需要用並查集維護可以相互修改的元素就可以了。
如果只有一個串是可修改的,相當於邊是有向邊,不難證明如下結論:對每個連通塊,如果它有環,那麼需要多加一條邊。否則和無向圖是一樣的。

#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;
set<pair<int
,int>
> s; vector<int> to[100010],bel[100010]; int a[100010],b[100010],fa[100010],n,v,ord[200010],que[100010],in[100010],hd,tl,tot; char s1[100],s2[100]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int main() { int ans=0,a1,b1,x; pair<int,int> p; scanf("%d",&n); scanf("%s",s1); for
(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%s",s2); for (int i=1;i<=n;i++) scanf("%d",&b[i]); if (s1[0]=='C'&&s2[0]=='C') { for (int i=1;i<=n;i++) if (a[i]!=b[i]) { printf("-1\n"); return 0; } printf
("0\n"); return 0; } for (int i=1;i<=100000;i++) fa[i]=i; for (int i=1;i<=n;i++) if (find(a[i])!=find(b[i])) { ans++; fa[fa[a[i]]]=fa[b[i]]; } if (s1[0]==s2[0]) { printf("%d\n",ans); return 0; } for (int i=1;i<=n;i++) if (a[i]!=b[i]) { ord[++v]=a[i]; ord[++v]=b[i]; } sort(ord+1,ord+v); v=unique(ord+1,ord+v+1)-ord-1; for (int i=1;i<=v;i++) fa[i]=i; for (int i=1;i<=n;i++) if (a[i]!=b[i]) { a1=lower_bound(ord+1,ord+v+1,a[i])-ord; b1=lower_bound(ord+1,ord+v+1,b[i])-ord; to[a1].push_back(b1); in[b1]++; fa[find(a1)]=find(b1); } for (int i=1;i<=v;i++) bel[find(i)].push_back(i); for (int i=1;i<=v;i++) if (fa[i]==i) { hd=1,tl=0; for (vector<int>::iterator it=bel[i].begin();it!=bel[i].end();it++) if (!in[*it]) que[++tl]=(*it); while (hd<=tl) { x=que[hd++]; for (vector<int>::iterator it=to[x].begin();it!=to[x].end();it++) { in[*it]--; if (!in[*it]) que[++tl]=*it; } } if (tl<bel[i].size()) ans++; } printf("%d\n",ans); }