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 }

 

 

posted @ 2013-01-17 19:52  proverbs  阅读(1640)  评论(0编辑  收藏  举报