[***]HZOJ 哪一天她能重回我身边
%%%神仙题。
居然是图论,我还一直以为是二分图或者啥数据结构。
直接说正解了,将数看作节点,牌看做边,从牌的正面的数想反面连边权为1的边,反面向正面连边权为0的边(注意用到成对存储的技巧,之后会非常巧妙地用到),可以发现就是要求反转几条边可以使每个点的出读小于等于1。那么每个联通图只可能是树或基环树。可以先dfs判断求出每个联通图的点数np和边数ne,若ne/2(双向边)>np,那么这个联通图不合法直接输出-1 -1即可。
1 void dfs(int x,int fa) 2 { 3 vi[x]=1;np++; 4 for(int i=f(x);i;i=n(i)) 5 { 6 ne++; 7 if(v(i)!=fa) 8 if(!vi[v(i)])dfs(v(i),x); 9 } 10 } 11 bool pd() 12 { 13 for(int i=1;i<=n*2;i++) 14 if(!vi[i]) 15 { 16 np=ne=0,dfs(i,0); 17 if(np<ne/2)return 1; 18 } 19 return 0; 20 }
接下来考虑他是树的情况:
对于确定的跟节点,翻转的边的个数就是将所有点指向父亲节点(可以动手画一下),可以用树形dp求得。但是要枚举根节点吗?其实可以用到二次扫描和换根法,设以x为根要反转的边数为f[x],那么其实f[son]可以用f[x]更新:如果x->son的边权为1,则f[son]=f[x]-1,否则f[son]=f[x]+1.这样我们就解决了树的情况。
1 int f[MAXN],st,en,ned; 2 void dfs1(int x,int fa) 3 { 4 v[x]=1;f[x]=0; 5 for(int i=f(x);i;i=n(i)) 6 if(v(i)!=fa) 7 { 8 if(!v[v(i)]) 9 { 10 dfs1(v(i),x); 11 f[x]+=f[v(i)]+w(i); 12 } 13 else st=u(i),en=v(i),ned=i; 14 } 15 } 16 int f2[MAXN]; 17 vector<int> tem; 18 void dfs2(int x,int fa) 19 { 20 tem.push_back(f2[x]); 21 for(int i=f(x);i;i=n(i)) 22 if(v(i)!=fa && i!=ned && i!=(ned^1)) 23 { 24 if(w(i))f2[v(i)]=f2[x]-1; 25 else f2[v(i)]=f2[x]+1; 26 dfs2(v(i),x); 27 } 28 }
下面看基环树:
在dfs时找出环上的随机一条边记录,将它去掉按树处理,最后在考虑这条边的影响。那么边的成对储存就有用了,将边的编号%2就是它从u指向v的权值。
1 ned%=2; 2 if(f2[st]+ned==f2[en]+(ned^1))minn=2; 3 else minn=1; 4 ans+=min(f2[st]+ned,f2[en]+(ned^1));
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #define MAXN 200010 7 #define mod 998244353 8 #define LL long long 9 #define int LL 10 #define ma(x) memset(x,0,sizeof(x)) 11 using namespace std; 12 struct edge 13 { 14 int u,v,w,nxt; 15 #define u(x) ed[x].u 16 #define v(x) ed[x].v 17 #define w(x) ed[x].w 18 #define n(x) ed[x].nxt 19 }ed[MAXN*2]; 20 int first[MAXN],num_e=1; 21 #define f(x) first[x] 22 int T,n; 23 24 int np,ne; 25 bool v[MAXN],vi[MAXN]; 26 void dfs(int x,int fa) 27 { 28 vi[x]=1;np++; 29 for(int i=f(x);i;i=n(i)) 30 { 31 ne++; 32 if(v(i)!=fa) 33 if(!vi[v(i)])dfs(v(i),x); 34 } 35 } 36 bool pd() 37 { 38 for(int i=1;i<=n*2;i++) 39 if(!vi[i]) 40 { 41 np=ne=0,dfs(i,0); 42 if(np<ne/2)return 1; 43 } 44 return 0; 45 } 46 int f[MAXN],st,en,ned; 47 void dfs1(int x,int fa) 48 { 49 v[x]=1;f[x]=0; 50 for(int i=f(x);i;i=n(i)) 51 if(v(i)!=fa) 52 { 53 if(!v[v(i)]) 54 { 55 dfs1(v(i),x); 56 f[x]+=f[v(i)]+w(i); 57 } 58 else st=u(i),en=v(i),ned=i; 59 } 60 } 61 int f2[MAXN]; 62 vector<int> tem; 63 void dfs2(int x,int fa) 64 { 65 // v[x]=1; 66 tem.push_back(f2[x]); 67 for(int i=f(x);i;i=n(i)) 68 if(v(i)!=fa && i!=ned && i!=(ned^1)) 69 { 70 if(w(i))f2[v(i)]=f2[x]-1; 71 else f2[v(i)]=f2[x]+1; 72 // if(!v[v(i)]) 73 dfs2(v(i),x); 74 } 75 } 76 inline void add(int u,int v,int w); 77 signed main() 78 { 79 // freopen("back5.in","r",stdin); 80 // freopen("1.out","w",stdout); 81 82 cin>>T; 83 while(T--) 84 { 85 ma(f);ma(f2);ma(v);ma(vi);ma(first);num_e=1;tem.clear(); 86 scanf("%lld",&n); 87 int a,b; 88 for(int i=1;i<=n;i++) 89 { 90 scanf("%lld%lld",&a,&b); 91 add(a,b,1);add(b,a,0); 92 } 93 if(pd()){puts("-1 -1");continue;} 94 int minn=0,ans=0,ans2=1; 95 for(int i=1;i<=n*2;i++) 96 if(!v[i]) 97 { 98 st=en=ned=-1;tem.clear();minn=0; 99 dfs1(i,0); 100 f2[i]=f[i]; 101 dfs2(i,0); 102 if(st==-1) 103 { 104 sort(tem.begin(),tem.end()); 105 for(int j=0;j<tem.size();j++) 106 if(tem[j]==tem[0])minn++; 107 else break; 108 ans+=tem[0]; 109 } 110 else 111 { 112 ned%=2; 113 if(f2[st]+ned==f2[en]+(ned^1))minn=2; 114 else minn=1; 115 ans+=min(f2[st]+ned,f2[en]+(ned^1)); 116 } 117 ans2=(ans2*minn)%mod; 118 } 119 printf("%lld %lld\n",ans,ans2); 120 } 121 } 122 inline void add(int u,int v,int w) 123 { 124 ++num_e; 125 u(num_e)=u; 126 v(num_e)=v; 127 w(num_e)=w; 128 n(num_e)=f(u); 129 f(u)=num_e; 130 }
波澜前,面不惊。