18.09.09模拟赛T3。
本来以为是各种高深的图论算法,结果是dfs......
大致讲一下思路:
分为有环和无环两种情况。
连边的时候,为了方便搜索,双向连边,正向连1,反向连-1。
dfs时记录一个相对距离d。
第一遍dfs找环,最大答案是所有环长的gcd。最小答案是gcd的一个因数。
如果没有环,就进行第二次dfs。
每一条链分别dfs,链长即为最大相对距离和最小相对距离的差。
最大答案是所有链长之和,最小答案是3。
注意如果ans<3,要特判为无解。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define maxn 100010 5 #define maxm 2000010 6 using namespace std; 7 8 int n,m; 9 int hd[maxn],to[maxm],nx[maxm],val[maxm],ec=1; 10 int v[maxn],d[maxn],ve[maxm]; 11 int ans,mxd,mnd; 12 13 void edge(int af,int at,int kd) 14 { 15 to[++ec]=at; 16 nx[ec]=hd[af]; 17 val[ec]=kd; 18 hd[af]=ec; 19 } 20 21 int gcd(int x,int y) 22 { 23 return (!y)?x:gcd(y,x%y); 24 } 25 26 int abv(int x) 27 { 28 return (x>0)?x:(-x); 29 } 30 31 void o(int p) 32 { 33 v[p]=1; 34 for(int i=hd[p];i;i=nx[i]) 35 { 36 if(v[to[i]])ans=gcd(ans,abv(d[p]+val[i]-d[to[i]])); 37 else d[to[i]]=d[p]+val[i],o(to[i]); 38 } 39 } 40 41 void l(int p) 42 { 43 v[p]=1; 44 mxd=max(mxd,d[p]); 45 mnd=min(mnd,d[p]); 46 for(int i=hd[p];i;i=nx[i]) 47 { 48 if(ve[i])continue; 49 ve[i]=ve[i^1]=1; 50 d[to[i]]=d[p]+val[i]; 51 l(to[i]); 52 } 53 } 54 55 int main() 56 { 57 scanf("%d%d",&n,&m); 58 for(int i=1;i<=m;i++) 59 { 60 int ff,tt; 61 scanf("%d%d",&ff,&tt); 62 edge(ff,tt,1); 63 edge(tt,ff,-1); 64 } 65 for(int i=1;i<=n;i++)if(!v[i])o(i); 66 if(ans) 67 { 68 if(ans<3) 69 { 70 printf("-1 -1"); 71 return 0; 72 } 73 for(int i=3;i<=ans;i++) 74 { 75 if(ans%i)continue; 76 printf("%d %d",ans,i); 77 return 0; 78 } 79 } 80 memset(v,0,sizeof(v)); 81 for(int i=1;i<=n;i++) 82 { 83 if(v[i])continue; 84 mxd=mnd=d[i]=0; 85 l(i); 86 ans+=(mxd-mnd+1); 87 } 88 if(ans<3)printf("-1 -1"); 89 else printf("%d 3",ans); 90 return 0; 91 }