BZOJ 1064 [Noi2008]假面舞会
这题其实不是很难,就是我没写对。。
把情况想全了:
有很多个连通块(单向边看作双向边),对于每个连通块有这样几类情况:
1、
2、
3、
应该就是这几类吧~
现在先讨论最大值
第1类:对答案没有影响
第2类:环上的点数一定是答案的倍数
第3类:两个链的长度的差一定是答案的倍数
所以答案就是2、3的最大公约数(有2、3存在的情况下)
综上所述,先计算第1类,再就算2、3类。。
ps:我是一起做的,然后长跪不起了,最后抄的lyd神犇的。。。
有个技巧,就是把边权设为1和-1~
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdlib> 6 #include <cmath> 7 8 #define N 200000 9 #define M 4000000 10 11 using namespace std; 12 13 int head[N],next[M],to[M],len[M]; 14 bool vis[N],bh[M]; 15 int d[N]; 16 int n,m,cnt,ans,tmax,tmin,an; 17 18 inline void add(int u,int v,int w) 19 { 20 to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++; 21 } 22 23 inline void read() 24 { 25 memset(head,-1,sizeof head); cnt=0; 26 scanf("%d%d",&n,&m); 27 for(int i=1,a,b;i<=m;i++) 28 { 29 scanf("%d%d",&a,&b); 30 add(a,b,1); add(b,a,-1); 31 } 32 } 33 34 inline int gcd(int x,int y) 35 { 36 int ys; 37 while(y) 38 { 39 ys=x%y; 40 x=y; y=ys; 41 } 42 return x; 43 } 44 45 inline void dfs(int u) 46 { 47 vis[u]=true; 48 for(int i=head[u];~i;i=next[i]) 49 { 50 if(vis[to[i]]) 51 { 52 ans=gcd(ans,abs(d[u]+len[i]-d[to[i]])); 53 } 54 else 55 { 56 d[to[i]]=d[u]+len[i]; 57 dfs(to[i]); 58 } 59 } 60 } 61 62 inline void tree(int u) 63 { 64 vis[u]=true; 65 tmax=max(tmax,d[u]); 66 tmin=min(tmin,d[u]); 67 for(int i=head[u];~i;i=next[i]) 68 if(!vis[to[i]]) 69 { 70 bh[i]=bh[i^1]=true; 71 d[to[i]]=d[u]+len[i]; 72 tree(to[i]); 73 } 74 } 75 76 inline void go() 77 { 78 for(int i=1;i<=n;i++) 79 if(!vis[i]) dfs(i); 80 if(ans) 81 { 82 for(an=3;an<ans&&ans%an;an++); 83 } 84 else 85 { 86 memset(vis,0,sizeof vis); 87 for(int i=1;i<=n;i++) 88 if(!vis[i]) 89 { 90 tmax=tmin=d[i]=0; 91 tree(i); 92 ans+=tmax-tmin+1; 93 } 94 an=3; 95 } 96 if(ans<3) ans=an=-1; 97 printf("%d %d\n",ans,an); 98 } 99 100 int main() 101 { 102 read();go(); 103 return 0; 104 }
没有人能阻止我前进的步伐,除了我自己!