bzoj 1064
题意:戳这里
思路:很明显是一个图论模型。。
就两种图形:
1、图中存在环,那么就是所有环的gcd为最大答案。gcd的大于3的最小约数为最小答案
2、不存在环,那么是每个弱连通块的最长链之和为最大答案,最小答案为3。。
但是这一题最关键的是实现,实现技巧太赞了。。
首先,我们可以把每条有向边(u, v)拆成(u, v, 1), (v, u, -1)
那么对于第二情况,对于每一个联通块直接随便找一个bfs,然后最长链就是maxdist-mindist+1
对于第一种情况,可能出现环套环的情况,这样处理起来很麻烦。。
但实际上很容易发现对于大环套小环实际上大环可以转换成大环-小环剩下的小圈求gcd。。注意这里的小圈不一定是环,因为边有正有负。。
这样正好处理可以一遍dfs处理。。
说得很抽象。。直接看这位神犇博客的图吧。。
code:
1 #include <bits/stdc++.h> 2 #define M0(a) memset(a, 0, sizeof(a)) 3 #define x first 4 #define y second 5 #define vii vector< pair<int, int> >::iterator 6 using namespace std; 7 const int maxn = 100010; 8 vector< pair<int, int> > e[maxn]; 9 int n, m; 10 11 12 int vis[maxn], d[maxn]; 13 void init(){ 14 for (int i = 0; i <= n; ++i) e[i].clear(); 15 int u, v; 16 pair<int, int> tmp; 17 for (int i = 0; i < m; ++i){ 18 scanf("%d%d", &u, &v); 19 tmp.x = v, tmp.y = 1; 20 e[u].push_back(tmp); 21 tmp.x = u, tmp.y = -1; 22 e[v].push_back(tmp); 23 } 24 } 25 26 int ans; 27 void gao1(){ 28 int ans1 = ans, ans2 = ans; 29 if (ans1 < 3){ 30 puts("-1 -1"); return; 31 } 32 for (int j = 3; j <= ans; ++j) if (ans % j == 0){ 33 ans2 = j; break; 34 } 35 printf("%d %d\n", ans1, ans2); 36 } 37 38 39 int bfs(const int s){ 40 queue<int> q; 41 q.push(s), d[s] = 0, vis[s] = 1; 42 int u, v, w; 43 int maxdist= 0, mindist = 0; 44 while (!q.empty()){ 45 u = q.front(); 46 q.pop(); 47 for (vii it = e[u].begin(); it != e[u].end(); ++it){ 48 v = it->x, w = it->y; 49 if (vis[v]) continue; 50 d[v] = d[u] + w; 51 if (d[v] > maxdist) maxdist = d[v]; 52 if (d[v] < mindist) mindist = d[v]; 53 vis[v] = 1, q.push(v); 54 } 55 } 56 return maxdist - mindist + 1; 57 } 58 59 void gao2(){ 60 M0(vis), M0(d); 61 int ans1 = 0; 62 for (int i = 1; i <= n; ++i) if (!vis[i]) 63 ans1 += bfs(i); 64 if (ans1 < 3) puts("-1 -1"); 65 else printf("%d %d\n", ans1, 3); 66 } 67 68 void dfs(int u){ 69 vis[u] = 1; 70 int v; 71 for (vii it = e[u].begin(); it != e[u].end(); ++it){ 72 v = it->x; 73 if (vis[v]) 74 ans = __gcd(ans, abs(d[u] + it->y - d[v])); 75 else 76 d[v] = d[u] + it->y, dfs(v); 77 } 78 } 79 80 void solve(){ 81 M0(vis), M0(d); 82 ans = 0; 83 for (int i = 1; i <= n; ++i) if (!vis[i]) 84 dfs(i); 85 if (ans) gao1(); 86 else gao2(); 87 } 88 89 int main(){ 90 freopen("a.in", "r", stdin); 91 while (scanf("%d%d", &n, &m) != EOF){ 92 init(); 93 solve(); 94 } 95 }