CF1842H Tenzing and Random Real Numbers
神秘的题,神必的我。
原题的条件有点不太好看,考虑把每个数的范围变为 \([-0.5, 0.5]\)。
原题的要求形似 \(x_i + x_j \leq 0\),注意到这个式子是否成立只需要考虑绝对值较大的数的正负,考虑从小到大加入 \(x_i\)。
实际上并不需要考虑相等的情况,因为在一个连续段上选出指定的数的概率是 \(0\)。
假如绝对值大小关系已经确定了,那么每种情况下的概率是对称的,所以只要把方案数除以 \(n!2^n\) 即可。
那么直接状压,按绝对值从小到大加入元素,位运算判断这一位能否取正或者取负即可。
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 22;
const int maxm = maxn * maxn + maxn;
using ll = long long;
inline ll Pow(ll a, ll b = mod - 2) {
ll res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod, b >>= 1;
}
return res;
}
inline constexpr ll bit(const ll &x) {return 1ll << x;}
int f[bit(maxn)];
int V[maxn], W[maxn];
int n, m;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u, v, w;
cin >> w >> u >> v;
u--, v--;
if((V[u] & bit(v)) && ((W[u] >> v) & 1) != w) {
cout << 0;
return 0;
}
V[u] |= bit(v);
V[v] |= bit(u);
W[u] |= bit(v) * w;
W[v] |= bit(u) * w;
}
f[0] = 1;
for(int sta = 1; sta < bit(n); sta++) {
for(int u = 0; u < n; u++) {
if(!(sta & bit(u))) continue;
int bef = sta ^ bit(u);
int x = (!(W[u] & sta));
int y = ((V[u] & sta) == (W[u] & sta));
f[sta] = (f[sta] + (x + y) * f[bef] % mod) % mod;
}
}
int div = 1;
for(int i = 1; i <= n; i++) div = (ll)div * i % mod;
div = (ll)div * Pow(2, n) % mod;
cout << (ll)f[bit(n) - 1] * Pow(div) % mod;
}