交易
【问题描述】
给定n 点m 边有向无环图,其中没有入度的点被视为源点,没有出度的点被视为
汇点。保证源点和汇点数目相同。
考虑所有把源汇点两两配对,用两两点不相交的路径把它们两两连接的所有方案
如果这个方案中,把源点按标号排序后,得到的对应汇点序列的逆序数对的个数
是奇数,那么A给B 一块钱,否则B 给A 一块钱。
问最后A的收益,对一个 p 取模。n,m,p均为整数,p 为质数。
【输入格式】
第一行读入三个数,n,m,p,接下来m 行,读入有向边。
【输出格式】
一行,输出答案。
【样例输入】
4 4 1000003
2 1
2 4
3 1
3 4
【样例输出】
0
【数据规模与约定】
对于30%的数据,n<=100
对于100%的数据,1<=n<=600,1<=m<=50000.
式中k1,k2,...,kn是将序列1,2,...,n的元素次序交换k次所得到的一个序列,Σ号表示对k1,k2,...,kn取遍1,2,...,n的一切排列求和,那末数D称为n阶方阵相应的行列式
摘自百度。
构建矩阵$a_{i,j}$表示第i个起点到第j个终点。
如果有两条路径有交点,那么把这两条路径从交点到终点交换一下一定也进入了答案统计,而且交换了一次顺序,他们的交换次数的奇偶性是相反的。
可以抵消掉。
然后这个题的模数是质数,不用写辗转相除法。。。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define M 610 4 inline int read() { 5 char ch = getchar(); int x = 0, f = 1; 6 while(ch < '0' || ch > '9') { 7 if(ch == '-') f = -1; 8 ch = getchar(); 9 } 10 while('0' <= ch && ch <= '9') { 11 x = x * 10 + ch - '0'; 12 ch = getchar(); 13 } 14 return x * f; 15 } 16 struct Edge{ 17 int u, v, Next; 18 } G[M*M]; 19 int head[M], tot; 20 int in[M], out[M]; 21 int n, m, p; 22 int num; 23 inline void add(int u, int v) { 24 G[++ tot] = (Edge){u, v, head[u]}; 25 head[u] = tot; 26 } 27 int a[M][M]; 28 int p1[M], p2[M]; 29 int f[M], vis[M]; 30 inline int dfs(int x) { 31 if(vis[x]) return f[x]; 32 vis[x] = 1; 33 for(int i = head[x]; i != -1; i = G[i].Next) { 34 f[x] += dfs(G[i].v); 35 if(f[x] >= p) f[x] -= p; 36 } 37 return f[x]; 38 } 39 inline int get_det() { 40 int res = 1; 41 for(int i = 1; i <= num; ++ i) { 42 for(int j = i + 1; j <= num; ++ j) { 43 int x = a[i][i], y = a[j][i]; 44 while(y) { 45 int t = x / y; x %= y; swap(x, y); 46 for(int k = i; k <= num; ++ k) { 47 a[i][k] = (a[i][k] - 1ll * t * a[j][k] % p + p) % p; 48 } 49 for(int k = i; k <= num; ++ k) { 50 swap(a[i][k], a[j][k]); 51 } 52 res = -res; 53 } 54 } 55 if(a[i][i] == 0) return 0; 56 res = 1ll * res * a[i][i] % p; 57 } 58 return (res + p) % p; 59 } 60 int main() { 61 n = read(), m = read(), p = read(); 62 memset(head, -1, sizeof(head)); 63 for(int i = 1; i <= m; ++ i) { 64 int u = read(), v = read(); 65 ++ in[v]; ++ out[u]; 66 add(v, u); 67 } 68 for(int i = 1; i <= n; ++ i) { 69 if(!in[i]) { 70 p1[i] = ++ num; 71 } 72 } 73 num = 0; 74 for(int i = 1; i <= n; ++ i) { 75 if(!out[i]) { 76 p2[i] = ++ num; 77 } 78 } 79 for(int i = 1; i <= n; ++ i) { 80 if(!in[i]) { 81 for(int j = 1; j <= n; ++ j) { 82 vis[j] = f[j] = 0; 83 } 84 f[i] = vis[i] = 1; 85 for(int j = 1; j <= n; ++ j) { 86 if(!out[j]) { 87 dfs(j); 88 a[p1[i]][p2[j]] = f[j]; 89 } 90 } 91 } 92 } 93 printf("%d\n", get_det()); 94 }