P4284 [SHOI2014]概率充电器
换根 dp。
考虑算出每个点的概率
P
i
P_i
Pi,利用期望的线性性,
∑
P
i
\sum P_i
∑Pi 就是答案。
考虑先求出每个点通过自己或是子树的点通电的概率,设为
f
i
f_i
fi。
考虑加上一个子树时,概率怎么转移,设
w
w
w 为根
u
u
u 从子节点
v
v
v 及其子树通电的概率,即
w
=
f
v
∗
p
u
,
v
w = f_v * p_{u,v}
w=fv∗pu,v,这里
p
u
,
v
p_{u,v}
pu,v 表示连接
u
,
v
u,v
u,v 的导线的通电概率。
那么
f
u
=
f
u
+
w
−
f
u
×
w
f_u = f_u +w - f_u \times w
fu=fu+w−fu×w。
这里利用了一个小的容斥,即
P
(
A
∪
B
)
=
P
(
A
)
+
P
(
B
)
−
P
(
A
∩
B
)
=
P
(
A
)
+
P
(
B
)
−
P
(
A
)
×
P
(
B
)
P(A \cup B) = P(A) + P(B) − P(A \cap B) = P(A) + P(B) − P(A) \times P(B)
P(A∪B)=P(A)+P(B)−P(A∩B)=P(A)+P(B)−P(A)×P(B)。
然后考虑点
u
u
u 如何从父亲
f
a
fa
fa 处转移,此时要算出
f
a
fa
fa 不从
u
u
u 走时通电的概率,设为
P
a
P_a
Pa。
仿照开始求
f
f
f 的过程,令
w
=
f
u
×
p
u
,
f
a
w = f_u \times p_{u,fa}
w=fu×pu,fa,则有
f
f
a
=
P
a
+
w
−
P
a
×
w
f_{fa} = P_a + w - P_a \times w
ffa=Pa+w−Pa×w。
所以
P
a
=
f
f
a
−
w
1
−
w
P_a = \frac{f_{fa} - w}{1 - w}
Pa=1−wffa−w。(当
w
=
1
w = 1
w=1 时该式无意义,强行计算会导致 RE)。
所以
f
a
fa
fa 的子节点
u
u
u 真正通电的概率
P
(
u
)
=
f
u
+
(
P
a
×
p
u
,
f
a
)
−
f
u
×
(
P
a
×
p
u
,
f
a
)
P(u) = f_u + (P_a \times p_{u,fa}) - f_u \times (P_a \times p_{u,fa})
P(u)=fu+(Pa×pu,fa)−fu×(Pa×pu,fa)。
复杂度
O
(
n
)
O(n)
O(n)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline void read(int &x)
{
x = 0;
int f = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
f |= ch == '-';
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x = f ? -x : x;
return;
}
#define N 500005
int first[N], Next[N << 1], to[N << 1], tot;
double w[N << 1];
inline void add(int &x, int &y, double &z)
{
Next[++tot] = first[x];
first[x] = tot;
to[tot] = y;
w[tot] = z;
return;
}
double f[N];
void dfs1(int u, int pre)
{
for(int i = first[u]; i; i = Next[i])
{
int v = to[i];
if(v == pre)
{
continue;
}
dfs1(v, u);
f[u] = f[u] + w[i] * f[v] - f[u] * w[i] * f[v];
}
return;
}
void dfs2(int u, int pre)
{
for(int i = first[u]; i; i = Next[i])
{
int v = to[i];
if(v == pre)
{
continue;
}
if(f[v] * w[i] != 1)
{
double Pa = w[i] * (f[u] - f[v] * w[i]) / (1 - f[v] * w[i]);
f[v] = f[v] + Pa - f[v] * Pa;
}
dfs2(v, u);
}
return;
}
int n;
signed main()
{
int x, y;
double z;
read(n);
for(int i = 1; i < n; i++)
{
read(x), read(y);
scanf("%lf", &z);
z /= 100.0;
add(x, y, z);
add(y, x, z);
}
for(int i = 1; i <= n; i++)
{
scanf("%lf", &f[i]);
f[i] /= 100.0;
}
dfs1(1, 0);
dfs2(1, 0);
double ans = 0.0;
for(int i = 1; i <= n; i++)
{
ans += f[i];
}
printf("%0.6lf", ans);
return 0;
}
P3239 [HNOI2015]亚瑟王
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline void read(int &x)
{
x = 0;
int f = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
f |= ch == '-';
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x = f ? -x : x;
return;
}
#define N 505
int T, n, r;
double p[N], qp[N][N], f[N][N], g[N];
int d[N];
signed main()
{
read(T);
while(T--)
{
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
read(n), read(r);
for(int i = 1; i <= n; i++)
{
scanf("%lf%d", &p[i], &d[i]);
qp[i][0] = 1;
for(int j = 1; j <= r; j++)
{
qp[i][j] = qp[i][j - 1] * (1.0 - p[i]);
}
}
f[1][0] = qp[1][r];
f[1][1] = g[1] = 1.0 - qp[1][r];
for(int i = 2; i <= n; i++)
{
for(int j = 0; j <= min(i, r); j++)
{
if(j)
{
f[i][j] += f[i - 1][j - 1] * (1.0 - qp[i][r - j + 1]);
}
if(i > j)
{
f[i][j] += f[i - 1][j] * qp[i][r - j];
}
}
}
for(int i = 2; i <= n; i++)
{
for(int j = 0; j <= min(i - 1, r); j++)
{
g[i] += f[i - 1][j] * (1.0 - qp[i][r - j]);
}
}
double ans = 0;
for(int i = 1; i <= n; i++)
{
ans += g[i] * d[i];
}
printf("%0.10lf\n", ans);
}
return 0;
}
P3232 [HNOI2013]游走
存边的时候没开 2 倍,居然 TLE。我还以为是我写丑了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline void read(int &x)
{
x = 0;
int f = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
f |= ch == '-';
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x = f ? -x : x;
return;
}
#define N 505
#define M 250005
int n, m;
int first[N], Next[M], to[M], tot;
inline void add(int x, int y)
{
Next[++tot] = first[x];
first[x] = tot;
to[tot] = y;
return;
}
struct edge
{
int fr, to;
};
edge e[M];
int deg[N];
double f[N][N], c[N], tmp[M];
inline void Gauss()
{
for(int i = 1; i <= n; i++)
{
int pos = i;
while(pos <= m && !f[pos][i])
{
pos++;
}
for(int j = 1; j <= n; j++)
{
swap(f[i][j], f[pos][j]);
}
for(int j = 1; j <= n; j++)
{
if(i == j)
{
continue;
}
double rate = f[j][i] / f[i][i];
for(int k = i; k <= n; k++)
{
f[j][k] -= rate * f[i][k];
}
c[j] -= rate * c[i];
}
}
return;
}
signed main()
{
read(n), read(m);
for(int i = 1; i <= m; i++)
{
read(e[i].fr), read(e[i].to);
add(e[i].fr, e[i].to), add(e[i].to, e[i].fr);
deg[e[i].fr]++, deg[e[i].to]++;
}
c[1] = 1;
for(int i = 1; i < n; i++)
{
f[i][i] = 1;
for(int j = first[i]; j; j = Next[j])
{
int v = to[j];
f[i][v] = -1.0 / deg[v];
}
}
f[n][n] = 1;
Gauss();
for(int i = 1; i <= m; i++)
{
tmp[i] = ((c[e[i].fr] / f[e[i].fr][e[i].fr]) / deg[e[i].fr]) + ((c[e[i].to] / f[e[i].to][e[i].to]) / deg[e[i].to]);
}
sort(tmp + 1, tmp + m + 1);
double ans = 0;
for(int i = 1; i <= m; i++)
{
ans += tmp[i] * (m - i + 1);
}
printf("%0.3lf", ans);
return 0;
}
P5299 [PKUWC2018]Slay the Spire
计数神题。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline void read(int &x)
{
x = 0;
int f = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
f |= ch == '-';
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x = f ? -x : x;
return;
}
const int mod = 998244353;
#define N 3005
bool cmp(int a, int b)
{
return a > b;
}
int C[N][N];
inline void init()
{
C[0][0] = 1;
for(int i = 1; i < N; i++)
{
C[i][0] = 1;
for(int j = 1; j <= i; j++)
{
C[i][j] = (1ll * C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
return;
}
int n, m, k;
int buf[N], atk[N];
int f[N][N][2], g[N][N][2];
signed main()
{
init();
int T;
read(T);
while(T--)
{
read(n), read(m), read(k);
for(int i = 1; i <= n; i++)
{
read(buf[i]);
}
for(int i = 1; i <= n; i++)
{
read(atk[i]);
}
sort(buf + 1, buf + n + 1, cmp), sort(atk + 1, atk + n + 1, cmp);
f[0][0][0] = f[0][0][1] = 1;
for(int i = 1; i <= n; i++)
{
f[i][0][1] = 1;
for(int j = 1; j <= i; j++)
{
f[i][j][0] = (1ll * f[i - 1][j - 1][1] * buf[i]) % mod;
f[i][j][1] = (f[i - 1][j][1] + f[i][j][0]) % mod;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= i; j++)
{
g[i][j][0] = ((1ll * C[i - 1][j - 1] * atk[i]) % mod + g[i - 1][j - 1][1]) % mod;
g[i][j][1] = (g[i - 1][j][1] + g[i][j][0]) % mod;
}
}
int ans = 0;
for(int i = 0; i < k - 1; i++)
{
for(int j = 1; j <= n; j++)
{
ans = (1ll * f[n][i][1] * g[j][k - i][0] % mod * C[n - j][m - k] % mod + ans) % mod;
}
}
for(int i = 0; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
ans = (1ll * f[i][k - 1][0] * atk[j] % mod * C[2 * n - i - j][m - k] % mod + ans) % mod;
}
}
printf("%d\n", ans);
}
return 0;
}
后面的就不在蒟蒻能力范围内了。
q
w
q
qwq
qwq。