BZOJ1064: [Noi2008]假面舞会 图论
这个题很乱他的图首先是一个无向图我们在这里面找到无向环和有向环,用无向环的长度和有向环的长度差的gcd来更新答案,一个图一定可以由若干个简单环和边组成我们可以由dfs来找到这些,我们正向边为1反向边为-1把无向图变成有向图.
如果这个图里没有这个限制那么他就一定是,一群橄榄,那么我们记录一下最长橄榄就好了,这个实质是找最长不同链,那么他肯定不会对之前的情况造成任何影响,因为有向环或无向环的贡献长度一定小于最大橄榄.
#include<cstdio> #include<cstring> #include<iostream> #define N 100010 #define M 1000010 using namespace std; inline int abs(int x) { return x<0?0-x:x; } inline int read() { int sum=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') { sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar(); } return sum; } struct Tr { int to,next,w; }c[M<<1]; int n,m,head[N],t,ans,dis[N]; bool visit[N],in[N]; int Max,have,Min; inline void add(int x,int y,int z) { c[++t].to=y; c[t].next=head[x]; head[x]=t; c[t].w=z; } inline void Init() { n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); add(x,y,1); add(y,x,-1); } } int gcd(int x,int y) { return x==0?y:gcd(y%x,x); } inline void get(int x) { if(!x)return; ans=gcd(ans,abs(x)); } void dfs(int x,int now) { visit[x]=1; in[x]=1; dis[x]=now; if(now>Max) Max=now; if(now<Min) Min=now; for(int i=head[x];i;i=c[i].next) if(visit[c[i].to]) { if(in[c[i].to]) get(now+c[i].w-dis[c[i].to]); } else dfs(c[i].to,now+c[i].w); in[x]=0; } inline void work() { for(int i=1;i<=n;i++) if(!visit[i]) { Max=-0x3f3f3f3f; Min=0x7f7f7f7f; dfs(i,0); have+=Max-Min+1; } } inline void print() { if(!ans) { if(have<3) printf("-1 -1"); else printf("%d 3",have); } else { if(ans<3) printf("-1 -1"); else { int Ans=ans; for(int i=3;i<ans;i++) if(ans%i==0) { Ans=i; break; } printf("%d %d",ans,Ans); } } } int main() { Init(); work(); print(); return 0; }
苟利国家生死以, 岂因祸福避趋之。