2017.7.10 noi2008 假面舞会
首先,可以把每个人看成一个点,能看见谁就相当于两个人之间有一个单向边,这样就可以把关系看成几个连通图。
对于每个连通图,有三种情况:
1.所有边数之和的最大公约数
2.正向边和反向边差的绝对值的最大公约数
3.是一条链
记录的时候可以把正向边记为+1,反向边记为-1,遍历的时候只要记录图中的加和 就可以得知前两种情况,然后取gcd就是max,min是最小的、大于3的、max的约数。
如果在最后没有找到环,说明只有链能限制,这时就算出每个连通图中最长链,然后加和为max,min就是3了。
而如果有环,那么只能按环算,因为链无论如何也能满足,而环不行。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std; 8 int read() 9 { 10 int ans=0;char q=getchar(); 11 while(q<'0'||q>'9')q=getchar(); 12 while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} 13 return ans; 14 } 15 int gcd(int x,int y){return y==0?x:gcd(y,x%y);} 16 int abss(int x){return x<0?-x:x;} 17 int maxn(int a,int b){return a>b?a:b;} 18 int minn(int a,int b){return a<b?a:b;} 19 struct son 20 { 21 int v,next,w; 22 }; 23 son a1[6000001]; 24 int first[6000001],e; 25 26 void addbian(int u,int v,int w) 27 { 28 a1[e].w=w; 29 a1[e].v=v; 30 a1[e].next=first[u]; 31 first[u]=e++; 32 } 33 34 int n,m,u,o; 35 int vis[600001]; 36 int ans; 37 int w[600001]; 38 int maxl,minl; 39 40 void dfs(int fa,int x,int val) 41 { 42 //printf("x=%d val=%d\n",x,val); 43 vis[x]=1; 44 w[x]=val; 45 for(int i=first[x];i!=-1;i=a1[i].next) 46 { 47 int temp=a1[i].v; 48 if(temp==fa)continue; 49 if(vis[temp]) 50 { 51 if(val==0)continue; 52 ans=gcd(ans,abss(val+a1[i].w-w[temp])); 53 //printf("val=%d temp=%d ans=%d\n",val,temp,ans); 54 continue; 55 } 56 dfs(x,temp,val+a1[i].w); 57 } 58 } 59 60 void dfs2(int fa,int x,int val) 61 { 62 vis[x]=1; 63 maxl=maxn(maxl,val); 64 minl=minn(minl,val); 65 for(int i=first[x];i!=-1;i=a1[i].next) 66 { 67 int temp=a1[i].v; 68 if(vis[temp]||temp==fa)continue; 69 dfs2(x,temp,val+a1[i].w); 70 } 71 } 72 73 int main(){ 74 //freopen("party.in","r",stdin); 75 //freopen("party.out","w",stdout); 76 /////freopen("1.txt","r",stdin); 77 //freopen("2.txt","w",stdout); 78 mem(first,-1); 79 n=read();m=read(); 80 for(int i=1;i<=m;++i) 81 { 82 u=read();o=read(); 83 addbian(u,o,1); 84 addbian(o,u,-1); 85 } 86 //cout<<0; 87 for(int i=1;i<=n;++i) 88 { 89 if(vis[i])continue; 90 dfs(-1,i,0); 91 } 92 93 if(ans) 94 { 95 if(ans<3) 96 printf("-1 -1"); 97 else 98 { 99 printf("%d ",ans); 100 for(int i=3;i<=ans;++i) 101 if(!(ans%i)) 102 { 103 printf("%d",i); 104 break; 105 } 106 } 107 } 108 else 109 { 110 mem(w,0); 111 mem(vis,0); 112 for(int i=1;i<=n;++i) 113 { 114 if(vis[i])continue; 115 maxl=minl=0; 116 dfs2(-1,i,0); 117 //ans=maxn(maxl1+maxl2-1,ans); 118 ans+=(maxl-minl+1); 119 } 120 //printf("ans=%d\n",ans); 121 if(ans<3) 122 printf("-1 -1"); 123 else 124 printf("%d 3",ans); 125 } 126 127 //while(1); 128 return 0; 129 }