Graph · 图的联通 + 矩阵快速幂
2016-04-04 17:34
399 查看
来源:知乎
题意请戳上方↑
首先有两个很好玩的性质:
1.有向图的一个强连通分量的周期d = 所有环的长度的最大公约数
2.有向图的周期D = 所有强连通分量的周期di的最小公倍数
然后如果要求最小的
满足
,由于k可能很大,那么用类似倍增的思想来求,我一开始傻*用的二分,T出一片天。
另外因为
,矩乘的时候要压位。
题意请戳上方↑
首先有两个很好玩的性质:
1.有向图的一个强连通分量的周期d = 所有环的长度的最大公约数
2.有向图的周期D = 所有强连通分量的周期di的最小公倍数
然后如果要求最小的
满足
,由于k可能很大,那么用类似倍增的思想来求,我一开始傻*用的二分,T出一片天。
另外因为
,矩乘的时候要压位。
#include <bits/stdc++.h> using namespace std; #define f(i, x, y) for (int i=x; i<=y; i++) #define ff(i, x, y) for (int i=x; i<y; i++) #define pb push_back typedef long long LL; const int N = 1e5 + 10; const int mod = 1e9 + 7; int type, n, m; vector<int> a ; int scc, belong , sta , top, dfn , low , tim; int ans, d, D; bool check ; int dep ; map<int, int> prime; int gcd(int a, int b){ while ( b ) b^=a^=b^=a%=b; return a; } inline void dfs(int t, int depth){ dep[t]=depth; for (int i = 0, v; i<a[t].size(); ++i){ v = a[t][i]; if ( belong[v] == scc ) if ( ! dep[v] ) dfs(v, depth + 1); else d = gcd(d, abs( dep[t] - dep[v] ) + 1 ); } } inline void tarjan(int t){ dfn[t] = low[t] = ++ tim; check[t] = 1; sta[ ++ top ] = t; ff(i, 0, a[t].size()){ int v = a[t][i]; if ( ! dfn[ v ] ){ tarjan( v ); low[t] = min(low[t], low[v]); } else if (check[v]) low[t] = min(low[t], dfn[v]); } if ( dfn[t] == low[t] ){ ++ scc; int now = 0; while ( now != t ){ now = sta[ top -- ]; belong[now] = scc; check[now] = 0; } d=0; dfs(t, 1); f(i, 2, sqrt(d)) if ( d % i == 0 ){ int cnt = 0; while ( d % i == 0 ) d /= i, ++ cnt; prime[i] = max(prime[i], cnt); } if ( d > 1 ) prime[d] = max(prime[d], 1); } } /*--------------------divide-----------------------------*/ void calc(){ ans = D = 1; for (map<int, int>::iterator i=prime.begin(); i != prime.end(); ++ i) f(j, 1, (*i).second) ans = 1LL * ans * (*i).first % mod, D = D * (*i).first ; } typedef int arr[205]; struct mat{ arr a[205]; arr& operator [](int x){return a[x];} void init(){memset(a, 0, sizeof a);} }unit; int TMP[2][205][15]; mat operator *(mat A, mat B){ mat tmp; tmp.init(); memset(TMP, 0, sizeof TMP); f(i, 1, n) for (int j=1, k=1, l=0; j <= n; ++ j, ++ l){ if ( A[i][j] ) TMP[0][i][k] |= 1<<l; if ( j % 30 == 0 ) l = 0, ++ k; } f(i, 1, n) for (int j=1, k=1, l=0; j <= n; ++ j, ++ l){ if ( B[j][i] ) TMP[1][i][k] |= 1<<l; if ( j % 30 == 0 ) l = 0, ++ k; } int K = (n + 29) / 30; f(i, 1, n) f(j, 1, n) f(k, 1, K) if ( TMP[0][i][k] & TMP[1][j][k]) { tmp[i][j] = 1; break; } return tmp; } bool operator ==(mat A, mat B){ f(i, 1, n) f(j, 1, n) if ( A[i][j] ^ B[i][j] ) return 0; return 1; } mat qck(mat a, int b){ mat ret, ca; ca = a; f(i, 1, n) f(j, 1, n) ret[i][j] = (i==j); for(; b; b >>= 1, ca = ca * ca) if ( b & 1 ) ret = ret * ca; return ret; } mat A[205], Ad, AD[205]; void work(){ /*超时的二分判定 int l = 1, r = 1e9; ad = qck(unit, D); while ( l <= r ){ int mid = (l+r) >> 1; mat tmp = qck(unit, mid); if ( ! ( tmp == tmp * ad ) ) l = mid + 1; else r = mid - 1, K = mid; } */ //这里是用类似倍增的思想来求 A[i]是表示unit的2^i自乘 unit.init(); f(i, 1, n) ff(j, 0, a[i].size()) unit[i][a[i][j]] = 1; A[0] = unit; Ad = qck(A[0], D); AD[0] = A[0] * Ad; int t = 1; for ( ; ; ++ t) { A[t] = A[t-1] * A[t-1]; AD[t] = A[t] * Ad; if ( A[t] == A[t] * Ad ) break; } int P = 0; mat tmp; tmp.init(); f(i, 1, n) tmp[i][i] = 1; for (int i = t - 1; i >= 0; -- i) if ( ! ( tmp * A[i] == tmp * AD[i] ) ) P += 1<<i, tmp = tmp * A[i]; printf("%d %d\n", P + 1, ans); return ; } /*--------------------divide-----------------------------*/ int main(){ freopen("graph.in", "r", stdin); freopen("graph.out", "w", stdout); scanf("%d%d%d", &n, &m, &type); f(i, 1, m) { int x, y; scanf("%d%d", &x, &y); a[x].pb(y); } f(i, 1, n) if ( ! dfn[i] ) tarjan(i); calc(); if ( type != 1 ) printf("%d\n", ans); else work(); //debug(); return 0; }
相关文章推荐
- 算法竞赛入门经典--例题和课后训练(动态规划)
- PostgreSQL/bin
- (四)mybatis学习之原始Dao开发方式及与spring整合
- (三)mybatis学习之全局配置文件(sqlMapConfig.xml)
- 论美学的自我修养
- codevs 4163 求逆序对的数目 -树状数组法
- ListView控件绑定DataSet
- java中的引用
- Maven学习-使用Nexus搭建Maven私服
- (二)mybatis学习之入门增删改查
- python 输出中文乱码的解决方案
- Android基础部分再学习---activity的状态保存
- 面向对象的六大原则--单一职责原则
- DataSet之增删改查操作(DataGridView绑定)
- JavaScript之Ajax-4 XML解析(JavaScript中的XML、Ajax返回并解析XML)
- 一站式学习Wireshark(一):Wireshark基本用法
- (一)mybatis学习之初识mybatis
- Ubuntu Kylin安装笔记
- Retrofit初识
- Shell Script介绍及变量使用