Description
Solution
首先我们可以轻松预处理出满足条件的点集。
设 表示点集 的点组成州的方案数的满意度之和, 表示点集 的人口的 次方,当 为合法州区时, ,否则 。
那么,
这个问题可以用集合卷积优化,时间复杂度
集合卷积
上式等价与
所以多设一维状态 表示集合为 ,集合大小为 。当 时, 为
类似的,定义 。
所以有 。用 解决即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 25, maxm = maxn * maxn / 2, mod = 998244353;
int n, m, p, U;
int u[maxm], v[maxm], w[maxn], deg[maxn];
int sum[1 << 21], g[maxn][1 << 21], f[maxn][1 << 21], bcnt[1 << 21], inv[2100 * 2100 + 5];
int fa[maxn];
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline void inc(int &a, int b) {a += b; if (a >= mod) a -= mod;}
inline void dec(int &a, int b) {a -= b; if (a < 0) a += mod;}
inline int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void FWT(int *a, int n)
{
for (int i = 1; i < n; i <<= 1)
for (int j = 0; j < n; j += (i << 1))
for (int k = 0; k < i; ++k) inc(a[i + j + k], a[j + k]);
}
void UFWT(int *a, int n)
{
for (int i = 1; i < n; i <<= 1)
for (int j = 0; j < n; j += (i << 1))
for (int k = 0; k < i; ++k) dec(a[i + j + k], a[j + k]);
}
int main()
{
n = gi(); m = gi(); p = gi();
for (int i = 1; i <= m; ++i) u[i] = gi(), v[i] = gi();
for (int i = 1; i <= n; ++i) w[i] = gi();
inv[1] = 1;
for (int i = 2; i <= 2100 * 2100; ++i) inv[i] = (lint)(mod - mod / i) * inv[mod % i] % mod;
for (int i = 1; i < (1 << n); ++i) bcnt[i] = bcnt[i ^ (i & (-i))] + 1;
for (int i = 1; i < (1 << n); ++i) {
for (int j = 1; j <= n; ++j) {
if ((i >> (j - 1)) & 1) sum[i] += w[j];
deg[j] = 0; fa[j] = j;
}
for (int j = 1; j <= m; ++j)
if (((i >> (u[j] - 1)) & 1) && ((i >> (v[j] - 1)) & 1)) ++deg[u[j]], ++deg[v[j]], fa[find(u[j])] = find(v[j]);
int flag = 0, root = 0;
for (int j = 1; j <= n; ++j)
if ((i >> (j - 1)) & 1) {
if (deg[j] & 1) {flag = 1; break;}
if (!root) root = find(j);
else if (find(j) != root) {flag = 1; break;}
}
if (p == 0) sum[i] = 1;
else if (p == 2) sum[i] = (lint)sum[i] * sum[i] % mod;
if (flag) g[bcnt[i]][i] = sum[i];
sum[i] = inv[sum[i]];
}
U = 1 << n;
for (int i = 0; i <= n; ++i) FWT(g[i], U);
f[0][0] = 1;
FWT(f[0], U);
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < i; ++j)
for (int s = 0; s < U; ++s)
inc(f[i][s], (lint)f[j][s] * g[i - j][s] % mod);
UFWT(f[i], U);
for (int s = 0; s < U; ++s)
if (bcnt[s] != i) f[i][s] = 0;
else f[i][s] = (lint)f[i][s] * sum[s] % mod;
if (i != n) FWT(f[i], U);
}
printf("%d\n", f[n][U - 1]);
return 0;
}