UR 2 密码锁
Posted YYCJM From NPW nursery school
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UR 2 密码锁相关的知识,希望对你有一定的参考价值。
\[UR\ \ 2 密码锁\]
- \(myy\)的题
- 然而考场上只会\(O(3^N)\)的算法还因为时间问题只写了\(O(3^N*N)\)然后就被\(32\)位机卡常了只有\(26\)分,还搞得另外两个题没检查都爆零了,
myy:你们是我见过最差的一届 - 自己垃圾无话可说
- 部分分可以参考竞赛图求\(SCC\)的那种套路来做,就是先设一个什么\(f[s]\)表示集合\(s\)是\(SCC\)的概率,然后用一个类似背包的东西枚举子集来转移(其实这个做法有点强行套上一道以前的题没有考虑本题的性质
- 然而有更加优美的\(O(2^N*N^2)\)的做法,能够发现竞赛图缩点后一定形如一条链,考虑对链上的每一条边计数,为了方便可以假设最后一个点之后也会连着一条链,所以我们可以\(O(2^N)\)枚举链的前缀,然后这个前缀要全部向剩余的点连边,算一下概率,最后加在一起
- 考虑进一步优化上面的算法,发现我们一个大小为\(M\)的没有特殊的边的集合成为一个前缀的概率是\((\frac{1}{2})^{M*(N-M)}\),每加入一条特殊的边就是乘上\(2p\),考虑对大小为M的集合一起处理,最后一起乘以\((\frac{1}{2})^{M*(N-M)}\)就好了,然后其实我并不会第\(4\)个\(SubTask\)就直接讲正解吧,边的贡献可以直接枚举连通块来算,然后把每些边组成的联通块先用\(dp\)算出来在取这个集合时边的贡献,然后用背包合在一起,最后一起乘上那个\(2\)的多少次幂即可,因为边数很小,所以连通块的点数也很小,可以通过
#include <bits/stdc++.h>
typedef long long LL;
inline int read(int Num = 0, int Flag = 1)
{
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == ‘-‘)
Flag = -1;
for (; isdigit(ch); ch = getchar())
Num = Num * 10 + ch - ‘0‘;
return Num *= Flag;
}
template <typename T> bool chkmax(T &a, T b) { return a < b? a = b, true : false; }
template <typename T> bool chkmin(T &a, T b) { return a > b? a = b, true : false; }
const int MAXN = 50 + 5;
const int mod = 998244353;
const int base = 1e4;
int fpm(int x, int e)
{
int ret = 1;
for (; e; e >>= 1) {
if (e & 1)
ret = (LL)ret * x % mod;
x = (LL)x * x % mod;
}
return ret;
}
int N, M, mul_num;
std::vector<int> G[MAXN];
int from[MAXN], to[MAXN], p[MAXN];
int size, tot;
int id[MAXN], occur[MAXN];
void DFS_work(int u, int tot)
{
id[u] = size ++;
occur[u] = tot;
for (int i = 0; i < (int)G[u].size(); ++i) {
int v = G[u][i];
if (id[v] < 0) DFS_work(v, tot);
}
}
int sum[MAXN][MAXN];
int dp[MAXN][MAXN];
int main()
{
freopen("random.in", "r", stdin);
freopen("random.out", "w", stdout);
N = read(), M = read();
mul_num = fpm(base, N * (N-1));
for (int i = 1; i <= M; ++i) {
int u = read(), v = read(), w = read();
G[u].push_back(v);
G[v].push_back(u);
from[i] = u, to[i] = v;
p[i] = (LL)w * fpm(base, mod - 2) % mod;
}
int allblock_size = 0;
memset(id, -1, sizeof id);
for (int i = 1; i <= N; ++i) {
if (id[i] >= 0) continue;
size = 0;
tot ++;
DFS_work(i, tot);
allblock_size += size;
for (int s = 0; s < 1<<size; ++s) {
int coe = 1;
for (int j = 1; j <= M; ++j) {
if (occur[from[j]] == tot && (((s >> id[from[j]]) ^ (s >> id[to[j]])) & 1)) {
coe = coe * 2 % mod;
coe = (LL)coe * ((s >> id[from[j]]) & 1? p[j] : mod + 1 - p[j]) % mod;
}
}
int bit = __builtin_popcount(s);
sum[tot][bit] = (sum[tot][bit] + coe) % mod;
}
}
dp[0][0] = 1;
for (int i = 0; i < tot; ++i) {
for (int j = 0; j <= N; ++j) {
for (int k = 0; k + j <= N; ++k)
dp[i+1][j+k] = (dp[i+1][j+k] + (LL)dp[i][j] * sum[i + 1][k] % mod) % mod;
}
}
int ans = 0;
assert(allblock_size == N);
for (int i = 1; i <= N; ++i) {
ans = (ans + (LL)dp[tot][i] * fpm((mod + 1) / 2, i * (N-i)) % mod) % mod;
}
printf("%lld\n", (LL)ans * mul_num % mod);
return 0;
}
以上是关于UR 2 密码锁的主要内容,如果未能解决你的问题,请参考以下文章
Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段
连接MySQL出现错误:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)(代码片段
修改MySQL密码报错“ERROR 1819 (HY000): Your password does not satisfy the current policy requirements“(代码片段