http://www.lydsy.com/JudgeOnline/problem.php?id=1064
思路:第一眼看的时候以为是差分约束,但是是做不了的,不过能保证的就是这题绝对是图论题。。。(废话)
分联通块考虑,如果每个联通块都是没有有向环的话,那么各个联通块中,最长链就是最大答案,3就是最小答案。
只要有一个联通块有环,那么答案一定是这个环长度的因数,最大答案,就是这些环长度的gcd
不过,要是有这个非正常的环怎么办?
我们可以看到,4->3和2->3都指向了3,这怎么办?那么我们只要在一开始建图的时候,原来的有向边权值为1,再同时建一个反向边权值为-1,把有向图变成无向图。
为什么?,因为如图,4可以到3,2也可以到3,说明2的编号和4相同,所以2->3->4的路径实际上是"走出去一步,又走回来一步",也就是我常说的"有来有回",按照我们刚才的建图方式,这个环的长度就是:1+1+1+1-1=3,事实上,答案也是如此,3和5编号相同,2和4编号相同,这样图中实际上是只有3种面具。
1 #include2 #include 3 #include 4 #include 5 #include 6 int tot,go[2100005],next[2100005],first[2100005]; 7 int c[200005],dis[200005],vis[200005],n,m,len,val[2100005]; 8 int read(){ 9 int t=0,f=1;char ch=getchar();10 while (ch<'0'||ch>'9'){ if (ch=='-') f=-1;ch=getchar();}11 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}12 return t*f;13 }14 void insert(int x,int y,int z){15 tot++;16 go[tot]=y;17 next[tot]=first[x];18 first[x]=tot;19 val[tot]=z;20 }21 void add(int x,int y){22 insert(x,y,1);insert(y,x,-1);23 }24 int gcd(int a,int b){25 if (b==0) return a;26 else return gcd(b,a%b);27 }28 int bfs(int x){29 int h=1,t=1;c[1]=x;vis[x]=1;dis[x]=0;30 int mxdis=0,mndis=0;31 while (h<=t){32 int now=c[h++];33 for (int i=first[now];i;i=next[i]){34 int pur=go[i];35 if (vis[pur]){36 len=gcd(len,val[i]+dis[now]-dis[pur]);37 continue;38 }39 vis[pur]=1;40 c[++t]=pur;41 dis[pur]=dis[now]+val[i];42 mxdis=std::max(mxdis,dis[pur]);43 mndis=std::min(mndis,dis[pur]);44 }45 }46 return mxdis-mndis+1;47 }48 int main(){49 n=read();m=read();50 for (int i=1;i<=m;i++){51 int x=read(),y=read();52 add(x,y);53 }54 int sum=0;55 for (int i=1;i<=n;i++)56 if (!vis[i]) sum+=bfs(i);57 len=std::abs(len);58 if (len){59 if (len<3) {60 printf("-1 -1\n");61 return 0;62 }63 printf("%d ",len);64 for (int i=3;i<=len;i++)65 if (len%i==0) {66 printf("%d\n",i);67 break;68 }69 return 0;70 }else71 if (sum<3){72 printf("-1 -1\n");73 return 0;74 }else{75 printf("%d 3\n",sum);76 return 0;77 }78 }