zoukankan      html  css  js  c++  java
  • 交易

    【问题描述】
    给定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 }
  • 相关阅读:
    UDP最大传输字节
    [bzoj3994] [SDOI2015]约数个数和
    [bzoj3529] [Sdoi2014]数表
    [bzoj3309] DZY Loves Math
    [bzoj2693] jzptab
    [bzoj4407] 于神之怒加强版
    [bzoj3688] 折线统计
    [bzoj2301] [HAOI2011]Problem b
    [bzoj2820] YY的GCD
    [bzoj4559] [JLoi2016]成绩比较
  • 原文地址:https://www.cnblogs.com/iamqzh233/p/10079487.html
Copyright © 2011-2022 走看看