【数学】国庆集训作业

本文介绍了三个来自信息技术竞赛的题目,分别是概率充电器问题的动态规划求解,以及亚瑟王和游走两个问题的递归与概率转移。通过实例展示了如何运用概率和期望理论解决实际问题,涉及数据结构、动态规划和概率论等知识点。
摘要由CSDN通过智能技术生成

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=fvpu,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+wfu×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(AB)=P(A)+P(B)P(AB)=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+wPa×w
所以 P a = f f a − w 1 − w P_a = \frac{f_{fa} - w}{1 - w} Pa=1wffaw。(当 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值