交易

【问题描述】
给定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
", get_det());
94 }
原文地址:https://www.cnblogs.com/iamqzh233/p/10079487.html