UOJ #181. 【UR #12】密码锁(竞赛图+概率)
题解:
这个需要知道竞赛图统计强联通分量的个数的思路(套路)。
考虑竞赛图缩图之后是一条链,枚举这条链的一条边,把图分为左右两部分,之间的边是单向的就数量+1。
这题n比较大,不能暴力\(O(2^n)\)。
但是可以对每个特殊边的联通块做一遍,那么其它边都是\(1/2\)可以快速算。
最后是若干OGF卷起来,暴力即可。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 998244353;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const ll ni2 = ksm(2, mo - 2);
const int N = 40;
int n, m;
ll x, y, z;
ll aw[N * N], bw[N * N], cw[N * N];
ll a[N][N];
vector<int> e[N];
#define pb push_back
#define si size()
int bz[N], d[N], d0;
void dg(int x) {
if(bz[x]) return;
bz[x] = 1;
d[++ d0] = x;
ff(_y, 0, e[x].si) {
int y = e[x][_y];
dg(y);
}
}
ll f[N], g[N], h[N];
int p[N], p0, q[N], q0;
void juanji() {
fo(i, 0, n) h[i] = f[i], f[i] = 0;
fo(i, 0, n) if(h[i]) fo(j, 0, n - i) if(g[j]) {
f[i + j] = (f[i + j] + h[i] * g[j] % mo) % mo;
}
}
ll sum = 0;
void dfs(int x) {
if(x > d0) {
ll s = 1;
fo(i, 1, p0) fo(j, 1, q0)
s = s * a[p[i]][q[j]] % mo;
s = s * bw[p0 * q0] % mo;
if(p0 > 0 && p0 < n) sum = (sum + s * aw[p0 * (n - p0)] % mo) % mo;
g[p0] = (g[p0] + s) % mo;
return;
}
p[++ p0] = d[x];
dfs(x + 1);
p0 --;
q[++ q0] = d[x];
dfs(x + 1);
q0 --;
}
int main() {
scanf("%d %d", &n, &m);
fo(i, 1, n) {
fo(j, i + 1, n) a[i][j] = a[j][i] = 5000;
}
aw[0] = 1; fo(i, 1, n * n) aw[i] = aw[i - 1] * 5000 % mo;
fo(i, 0, n * n) bw[i] = ksm(aw[i], mo - 2);
cw[0] = 1; fo(i, 1, n * n) cw[i] = cw[i - 1] * 10000 % mo;
fo(i, 1, m) {
scanf("%lld %lld %lld", &x, &y, &z);
a[x][y] = z; a[y][x] = 10000 - z;
e[x].pb(y); e[y].pb(x);
}
f[0] = 1;
fo(i, 1, n) if(!bz[i]) {
d0 = 0;
dg(i);
fo(j, 0, n) g[j] = 0;
dfs(1);
juanji();
}
ll ans = 0;
fo(i, 1, n - 1) ans = (ans + f[i] * aw[i * (n - i)] % mo * cw[n * (n - 1) / 2 - i * (n - i)]) % mo;
ans = (ans + cw[n * (n - 1) / 2]) % mo;
ans = (ans % mo + mo) % mo;
ans = ans * cw[n * (n - 1) / 2] % mo;
pp("%lld\n", ans);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址