1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| #include <cstdio> using namespace std; typedef long long LL; template <class Type> void read(Type &x) { char c; bool flag = false; while ((c = getchar()) < '0' || c > '9') c == '-' && (flag = true); x = c - '0'; while ((c = getchar()) >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0'; flag && (x = ~x + 1); } template <class Type> void write(Type x) { x < 0 && (putchar('-'), x = ~x + 1); x > 9 && (write(x / 10), 0); putchar(x % 10 + '0'); } const int N = 21, M = 1 << N, K = 220, mod = 998244353; int cnt[M], inv[M], g[N + 1][M], f[N + 1][M]; int n, m, p, w[N]; struct Edge { int u, v; } e[K]; int binpow (int b, int k = mod - 2) { int res = 1; while (k) { k & 1 && (res = (LL)res * b % mod); b = (LL)b * b % mod; k >>= 1; } return res; } namespace DSU { int p[N], d[N]; void init() { for (int i = 0; i < n; i++) p[i] = i, d[i] = 0; } int fa (int x) { return p[x] == x ? x : p[x] = fa(p[x]); } void merge (int x, int y) { d[x]++, d[y]++; p[fa(x)] = fa(y); } bool check (int x) { int s = 0; for (int i = 0; i < n; i++) s += p[i] == i; if (s > n - x + 1) return true; for (int i = 0; i < n; i++) if (d[i] & 1) return true; return false; } } void fwt (int *x, int op) { for (int mid = 1; mid < 1 << n; mid <<= 1) for (int i = 0; i < 1 << n; i += mid << 1) for (int j = 0; j < mid; j++) (x[i | j | mid] += x[i | j] * op) %= mod; } int main () { read(n), read(m), read(p); for (int i = 1; i <= m; i++) { read(e[i].u), read(e[i].v); e[i].u--, e[i].v--; } for (int i = 0; i < n; i++) read(w[i]); for (int i = 0; i < 1 << n; i++) { int tot = 0; for (int j = 0; j < n; j++) tot += (i >> j & 1) * w[j]; DSU::init(); for (int j = 1; j <= m; j++) i >> e[j].u & 1 && i >> e[j].v & 1 && (DSU::merge(e[j].u, e[j].v), 0); cnt[i] = cnt[i >> 1] + (i & 1); if (DSU::check(cnt[i])) g[cnt[i]][i] = binpow(tot, p); inv[i] = binpow(binpow(tot, p)); } for (int i = 0; i <= n; i++) fwt(g[i], 1); f[0][0] = 1; fwt(f[0], 1); for (int i = 1; i <= n; i++) { for (int j = 0; j <= i - 1; j++) for (int k = 0; k < 1 << n; k++) (f[i][k] += (LL)f[j][k] * g[i - j][k] % mod) %= mod; fwt(f[i], -1); for (int j = 0; j < 1 << n; j++) f[i][j] = cnt[j] == i ? (LL)f[i][j] * inv[j] % mod : 0; i ^ n && (fwt(f[i], 1), 0); } write((f[n][(1 << n) - 1] + mod) % mod); return 0; }
|