[Codeforces] probabilities (R1600) Part.1

[Codeforces] probabilities (R1600) Part.1

题单:https://codeforces.com/problemset?tags=probabilities,0-1600

9A. Die Roll

原题指路:https://codeforces.com/problemset/problem/9/A

题意

三个人丢写着数字1∼61\sim 616的六面骰子,其中前两人得到的数字分别为a,b  (1≤a,b≤b)a,b\ \ (1\leq a,b\leq b)a,b  (1a,bb).若第三个人得到的数字不小于另外两个人得到的数字,则他胜.求他胜的概率,输出既约分数的形式.

思路

显然ans=6−max⁡{a,b}+16ans=\dfrac{6-\max\{a,b\}+1}{6}ans=66max{a,b}+1.

代码

void solve() {
	int a, b; cin >> a >> b;
	
	int up = 6 - max(a, b) + 1, down = 6;
	int g = gcd(up, down);
	up /= g, down /= g;
	cout << up << '/' << down;
}

int main() {
	solve();
}


107B. Basketball Team

原题指路:https://codeforces.com/problemset/problem/107/B

题意

小明是包含nnn个队员的队伍中的一员.队员来自不同专业.有编号1∼m1\sim m1mmmm个专业,其中人数分别为s1,⋯ ,sns_1,\cdots,s_ns1,,sn,小明来自专业h  (1≤h≤m)h\ \ (1\leq h\leq m)h  (1hm).求小明至少有一个同专业的队友的概率,误差不超过1e−61\mathrm{e}-61e6.若组成队伍的人数不足,输出−1-11.

第一行输入三个整数n,m,h  (1≤n≤100,1≤m≤1000,1≤h≤m)n,m,h\ \ (1\leq n\leq 100,1\leq m\leq 1000,1\leq h\leq m)n,m,h  (1n100,1m1000,1hm).第二行输入mmm个整数s1,⋯ ,sn  (1≤si≤100)s_1,\cdots,s_n\ \ (1\leq s_i\leq 100)s1,,sn  (1si100),其中shs_hsh包含小明.

思路

111减不含队友的概率即可.

代码

void solve() {
	int n, m, h; cin >> n >> m >> h;
	vi s(m);
	for (int i = 0; i < m; i++) cin >> s[i];
	
	n--, s[--h]--;  // 除掉小明
	int sum = 0;
	for (int i = 0; i < m; i++) sum += s[i];

	if (sum < n) {
		cout << -1;
		return;
	}

	double ans = 1;
	for (int i = 0; i < n; i++) ans *= 1 - (double)s[h] / (sum--);
	cout << fixed << setprecision(12) << 1 - ans << endl;
}

int main() {
	solve();
}


312B. Archer

原题指路:https://codeforces.com/problemset/problem/312/B

题意 (2 s2\ \mathrm{s}2 s)

A和B打枪,A先手,他们射中的概率分别为ab\dfrac{a}{b}bacd\dfrac{c}{d}dc.第一个射中者胜.求A获胜的概率,误差不超过1e61\mathrm{e}61e6.

第一行输入四个整数a,b,c,d  (1≤a,b,c,d≤1000,0<ab,cd<1)a,b,c,d\ \ \left(1\leq a,b,c,d\leq 1000,0<\dfrac{a}{b},\dfrac{c}{d}<1\right)a,b,c,d  (1a,b,c,d1000,0<ba,dc<1).

思路

两人各打一次为一轮,则一轮中两人都没射中的概率为q=(1−ab)(1−cd)q=\left(1-\dfrac{a}{b}\right)\left(1-\dfrac{c}{d}\right)q=(1ba)(1dc).设A获胜前经过了nnn轮,则ans=p∑i=0n−1qi\displaystyle ans=p\sum_{i=0}^{n-1} q^ians=pi=0n1qi.令n→∞n\rightarrow\inftynans=p1−qans=\dfrac{p}{1-q}ans=1qp.

代码

void solve() {
	int a, b, c, d; cin >> a >> b >> c >> d;
	double p = (double)a / b, q = (1 - (double)c / d) * (1 - (double)a / b);
	cout << fixed << setprecision(12) << p / (1 - q);
}

int main() {
	solve();
}


345A. Expecting Trouble

原题指路:https://codeforces.com/problemset/problem/345/A

题意 (2 s)(2\ \mathrm{s})(2 s)

给定一个0−10-101序列,其中000表示好日子,111表示坏日子,???表示有ppp的概率为坏日子,有(1−p)(1-p)(1p)的概率为好日子.求坏日子的期望天数.

思路

直接计算即可.

本题是节日题,要求用Ada语言实现.

代码

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
 
procedure a is
	str: string(1..100);
	l: natural;
	x, p: float;
	
begin
	get_line(str, l);
	get(p); 
	x := 0.0;
 
	for i in 1..l loop
		if str(i) = '1' then x := x + 1.0;
		elsif str(i) = '?' then x := x + p;
		end if;	
	end loop;
	x := x / float(l);
	
	put(x, 0, 5, 0);
end;


453A. Little Pony and Expected Maximum

原题指路:https://codeforces.com/problemset/problem/453/A

题意

给定一个m  (1≤m≤1e5)m\ \ (1\leq m\leq1\mathrm{e}5)m  (1m1e5)个面的骰子,其中每个面上写有数字1∼m1\sim m1m.求投掷n  (1≤n≤1e5)n\ \ (1\leq n\leq1\mathrm{e}5)n  (1n1e5)次后能得到的最大值的期望.

思路

即给定nnn个取值范围为[1,m]⋂Z[1,m]\bigcap\mathbb{Z}[1,m]Z的随机变量X1,⋯ ,XnX_1,\cdots,X_nX1,,Xn,求max⁡{X1,⋯ ,Xn}\max\{X_1,\cdots,X_n\}max{X1,,Xn}的期望.

由离散随机变量的前缀和性:P(X=k)=P(X≤k)−P(X≤k−1)P(X=k)=P(X\leq k)-P(X\leq k-1)P(X=k)=P(Xk)P(Xk1).

E(X)=∑i=1mi⋅P(X=i)=∑i=1mi⋅[P(X≤i)−P(X≤i−1)]=∑i=1mi⋅[(im)n−(i−1m)n]\displaystyle E(X)=\sum_{i=1}^m i\cdot P(X=i)=\sum_{i=1}^m i\cdot [P(X\leq i)-P(X\leq i-1)]=\sum_{i=1}^m i\cdot\left[\left(\dfrac{i}{m}\right)^n-\left(\dfrac{i-1}{m}\right)^n\right]E(X)=i=1miP(X=i)=i=1mi[P(Xi)P(Xi1)]=i=1mi[(mi)n(mi1)n].

代码

void solve() {
	int m, n; cin >> m >> n;

	double ans = 0;
	for (int i = 1; 4i <= m; i++)
		ans += i * (pow((double)i / m, n) - pow((double)(i - 1) / m, n));
	cout << fixed << setprecision(8) << ans;
}

int main() {
	solve();
}


476B. Dreamoon and WiFi

原题指路:https://codeforces.com/problemset/problem/476/B

题意

某人在数轴上移动,初始时在原点.给定一个只包含字符’+‘和’-‘的字符串s1s_1s1,其中’+‘表示向右移动一个单位,’-‘表示向左移动一个单位.给定一个与s1s_1s1等长的、只包含字符’+‘、’-‘和’?‘的字符串s2s_2s2,其中’?‘等概率地取’+‘或’-'.分别进行操作s1s_1s1和操作s2s_2s2,求最后停在同一位置的概率,误差不超过1e−91\mathrm{e}-91e9.

第一行输入一个只包含字符’+‘和’-‘的字符串s1s_1s1.第二行输入一个与s1s_1s1等长的、只包含字符’+‘、’-‘和’?'的字符串s2s_2s2.数据保证两字符串的长度都不超过101010.

思路I

显然操作s1s_1s1后停在的位置targettargettarget可求得.

显然s2s_2s2中’?‘的位置不影响概率,可先求出只操作s2s_2s2中确定的字符后停在的位置lastlastlast,并统计s2s_2s2中’?'的个数unknownunknownunknown.

考察两终点的距离(相差的+1+1+1数)dis=target−lastdis=target-lastdis=targetlast.

disdisdisunknownunknownunknown奇偶性不同或unknown<abs(dis)unknown<abs(dis)unknown<abs(dis)时无解,概率为000.

②设从lastlastlast走到targettargettarget所需的步数为needneedneed,则need−(unknown−need)=∣dis∣need-(unknown-need)=|dis|need(unknownneed)=dis,解得need=⌊unknown+∣dis∣2⌋need=\left\lfloor\dfrac{unknown+|dis|}{2}\right\rfloorneed=2unknown+dis.

ans=Cunknownneed2unknownans=\dfrac{C_{unknown}^{need}}{2^{unknown}}ans=2unknownCunknownneed.

代码I

void solve() {
	string s1, s2; cin >> s1 >> s2;

	int target = 0;  // s1序列的终点
	for (int i = 0; i < s1.length(); i++)
		target += s1[i] == '+' ? 1 : -1;

	int last = 0;  // s2已知序列的终点
	int unknown = 0;  // s2中的?数
	for (int i = 0; i < s2.length(); i++) {
		if (s2[i] == '?') unknown++;
		else last += s2[i] == '+' ? 1 : -1;
	}
	
	int dis = target - last;  // 两终点相差的+1数
	if ((dis + unknown & 1) || unknown < abs(dis)) {
		cout << 0;
		return;
	}

	int need = unknown + abs(dis) >> 1;  // 到达终点所需的步数
	int ans = 1;
	for (int i = 0; i < need; i++) ans *= unknown - i;
	for (int i = 2; i <= need; i++) ans /= i;
	cout << fixed << setprecision(18) << (double)ans / (1 << unknown);
}

int main() {
	solve();
}

思路II

因’?‘的个数至多有101010个,可枚举每个’?'取何值.


思路III

dp[i][j]dp[i][j]dp[i][j]表示走到第iii个问号时坐标为jjj的概率.

状态转移方程dp[i][j]=dp[i−1][j−1]∗0.5+dp[i−1][j+1]∗0.5dp[i][j]=dp[i-1][j-1]*0.5+dp[i-1][j+1]*0.5dp[i][j]=dp[i1][j1]0.5+dp[i1][j+1]0.5.

因坐标可能为负,第二维加一个BASE=10BASE=10BASE=10的偏移值即可.

代码III

const int MAXN = 25;  // 两倍空间
const int BASE = 10;  // 偏移量
string s1, s2;
double dp[MAXN][MAXN];  // dp[i][j]表示走到第i个问号时坐标为j的概率

void solve() {
	cin >> s1 >> s2;
	
	int pos1 = 0, pos2 = 0, cnt = 0;
	for (int i = 0; i < s1.length(); i++) {
		pos1 += s1[i] == '+' ? 1 : -1;

		if (s2[i] == '?') cnt++;
		else pos2 += s2[i] == '+' ? 1 : -1;
	}

	dp[0][pos2 + BASE] = 1;
	for (int i = 1; i <= cnt; i++) {
		for (int j = -10; j <= 10; j++)  // 枚举下标
			dp[i][j + BASE] = dp[i - 1][j - 1 + BASE] * 0.5 + dp[i - 1][j + 1 + BASE] * 0.5;
	}
	cout << fixed << setprecision(18) << dp[cnt][pos1 + BASE];
}

int main() {
	solve();
}


839C. Journey

原题指路:https://codeforces.com/problemset/problem/839/C

题意 (2 s)(2\ \mathrm{s})(2 s)

给定一棵包含编号1∼n1\sim n1nnnn个节点的、边长都为111的树.某人从节点111出发,每次等概率地选择一个与当前节点相邻的且之前未经过的节点,行走到该节点,若不存在这样的节点,则结束.求经过的路径长度的期望,误差不超过1e−61\mathrm{e}-61e6.

第一行输入一个整数n  (1≤n≤1e5)n\ \ (1\leq n\leq 1\mathrm{e}5)n  (1n1e5).接下来(n−1)(n-1)(n1)行每行输入两个整数u,v  (1≤u,v≤n,u≤v)u,v\ \ (1\leq u,v\leq n,u\leq v)u,v  (1u,vn,uv),表示节点uuu与节点vvv间存在边.数据保证给定边构成一棵树.

思路

设以节点uuu为起点的的答案为dp[u]dp[u]dp[u].显然dp[u]=∑v∈sonudp[v]+1\displaystyle dp[u]=\sum_{v\in son_u} dp[v]+1dp[u]=vsonudp[v]+1.每个节点对期望的贡献为路径长度之和除以路径数.

代码

const int MAXN = 2e5 + 5;
int n;
vi edges[MAXN];

double dfs(int u, int fa) {  // 当前节点、前驱节点
	double res = 0;
	for (auto v : edges[u]) {
		if (v == fa) continue;

		res += dfs(v, u) + 1;
	}
	return sgn(res) < eps ? 0 : res / (edges[u].size() - (fa != -1));
}

void solve() {
	cin >> n;
	for (int i = 1; i < n; i++) {
		int u, v; cin >> u >> v;
		edges[u].push_back(v), edges[v].push_back(u);
	}
	cout << fixed << setprecision(12) << dfs(1, -1);
}

int main() {
	solve();
}


930B. Game with String

原题指路:https://codeforces.com/problemset/problem/930/B

题意 (2 s)(2\ \mathrm{s})(2 s)

给定一个长度为lenlenlen的字符串sss.现有操作:选一个整数k∈[0,len−1]k\in [0,len -1]k[0,len1],将sss循环左移kkk位,即变为t=sk+1⋯sns1⋯skt=s_{k+1}\cdots s_n s_1\cdots s_kt=sk+1sns1sk.初始时给定ttt的首字符,你可询问ttt串的某位置的另一字符,问能唯一确定kkk的概率,误差不超过1e−61\mathrm{e}-61e6.注意可能能确定但非一定能唯一确定视为不能确定.

第一行输入一个长度不超过500050005000的、只包含小写英文字母的字符串.

思路

设与字符ch1ch_1ch1相距lenlenlen的字符为ch2ch_2ch2.考察三元组(ch1,len,ch2)(ch_1,len,ch_2)(ch1,len,ch2),则当且仅当这样的三元组在串中恰出现一次才能唯一确定kkk.

循环移位相当于将sss倍增.cnt[ch1][len][ch2]cnt[ch_1][len][ch_2]cnt[ch1][len][ch2]表示字符ch1ch_1ch1相距lenlenlen的字符为ch2ch_2ch2的出现次数.枚举每个下标作为首字符,预处理出所有的cnt[][][]cnt[][][]cnt[][][],统计cnt[][][]=1cnt[][][]=1cnt[][][]=1的个数即可.

代码

const int MAXN = 5005, MAXM = 26;
int n;
string s;
int cnt[MAXM][MAXN][MAXM];  // cnt[ch1][len][ch2]表示与字符ch1相距len的字符为ch2的出现次数

void solve() {
	cin >> s;
	n = s.length();

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (i == j) continue;

			int len = j - i;
			if (len < 0) len += n;
			cnt[s[i] - 'a'][len][s[j] - 'a']++;
		}
	}

	int ans = 0;
	for (int i = 0; i < 26; i++) {  // 枚举字符
		int res = 0;
		for (int j = 1; j < n; j++) {  // 枚举长度
			int tot = 0;  // cnt[][][]为1的个数
			for (int k = 0; k < 26; k++) tot += cnt[i][j][k] == 1;
			res = max(res, tot);
		}
		ans += res;
	}
	cout << fixed << setprecision(12) << (double)ans / n;
}

int main() {
	solve();
}


1459A. Red-Blue Shuffle

原题指路:https://codeforces.com/problemset/problem/1459/A

题意 (2 s)(2\ \mathrm{s})(2 s)

有编号1∼n1\sim n1nnnn张卡片,每张卡片上分别有一个红色数码r1,⋯ ,rnr_1,\cdots,r_nr1,,rn和蓝色数码b1,⋯ ,bnb_1,\cdots,b_nb1,,bn.现将所有卡片排序,等概率地对应一个1∼n1\sim n1n的全排列,后依次读出每张卡片上的红色数码得到数字RRR,依次读出每张卡片上的蓝色数码得到数字BBB.若R>BR>BR>B则红色胜出;若R<BR<BR<B则蓝色胜出;否则平局.若红色胜出的概率严格大,输出"RED";若蓝色胜出的概率严格大,输出"BLUE";否则输出"EQUAL".

t  (1≤t≤100)t\ \ (1\leq t\leq 100)t  (1t100)组测试数据.每组测试数据第一行输入一个整数n  (1≤n≤1000)n\ \ (1\leq n\leq 1000)n  (1n1000).第二行输入nnn个数码r1,⋯ ,rnr_1,\cdots,r_nr1,,rn.第三行输入nnn个数码b1,⋯ ,bnb_1,\cdots,b_nb1,,bn.

思路

对每个下标i∈[1,n]i\in[1,n]i[1,n]:

(1)若ri=bir_i=b_iri=bi,显然该数码对双方获胜的概率无影响.

(2)若ri≠bir_i\neq b_iri=bi,更新s[i]>t[i]s[i]>t[i]s[i]>t[i]s[i]<t[i]s[i]<t[i]s[i]<t[i]的下标的个数cnt1cnt1cnt1cnt2cnt2cnt2.

​ ①若最终cnt1>cnt2cnt1>cnt2cnt1>cnt2,则红色胜出的概率严格大.

​ ②若最终cnt1<cnt2cnt1<cnt2cnt1<cnt2,则蓝色胜出的概率严格大.

​ ③若最终cnt1=cnt2cnt1=cnt2cnt1=cnt2,则两颜色胜出的概率相等.

代码

void solve() {
	int n; cin >> n;
	string s, t; cin >> s >> t;

	int cnt1 = 0, cnt2 = 0;  // s[i]>和<t[i]的个数
	for (int i = 0; i < n; i++) {
		if (s[i] != t[i]) {
			if (s[i] > t[i]) cnt1++;
			else cnt2++;
		}
	}

	if (cnt1 == cnt2) cout << "EQUAL" << endl;
	else cout << (cnt1 > cnt2 ? "RED" : "BLUE") << endl;
}

int main() {
	CaseT  // 单测时注释掉该行
	solve();
}


1461C. Random Events

原题指路:https://codeforces.com/problemset/problem/1461/C

题意 (2 s)(2\ \mathrm{s})(2 s)

给定一个1∼n1\sim n1n的排列a1,⋯ ,ana_1,\cdots,a_na1,,an.现有mmm个操作,每个操作记作(r,p)(r,p)(r,p),表示有ppp的概率将a[1...r]a[1...r]a[1...r]升序排列.依次做mmm个操作,求最后将序列升序排列的概率,误差不超过1e−61\mathrm{e}-61e6.

t  (1≤t≤100)t\ \ (1\leq t\leq 100)t  (1t100)组测试数据.每组测试数据第一行输入两个整数n,m  (1≤n,m≤1e5)n,m\ \ (1\leq n,m\leq 1\mathrm{e}5)n,m  (1n,m1e5).第二行输入一个1∼n1\sim n1n的排列a1,⋯ ,ana_1,\cdots,a_na1,,an.接下来mmm行每行输入一个整数r  (1≤r≤n)r\ \ (1\leq r\leq n)r  (1rn)和一个实数p  (0≤p≤1)p\ \ (0\leq p\leq 1)p  (0p1),表示一个操作.数据保证所有测试数据的nnn之和、mmm之和都不超过1e51\mathrm{e}51e5.

思路

记最大的 s.t. ai!=i\ s.t.\ a_i!=i s.t. ai!=i的下标iiipospospos.显然答案与r<posr<posr<pos的操作无关,则只需考察r≥posr\geq posrpos的操作,将它们排序失败的概率(1−p)(1-p)(1p)相乘后,用111减去该概率即可.

代码

void solve() {
	int n, m; cin >> n >> m;
	vi a(n + 1);
	for (int i = 1; i <= n; i++) cin >> a[i];

	int pos = n;
	while (pos >= 1 && a[pos] == pos) pos--;

	double ans = pos ? 1 : 0;
	while (m--) {
		int r; double p; cin >> r >> p;
		if (r >= pos) ans *= 1 - p;
	}
	cout << fixed << setprecision(12) << 1 - ans << endl;
}

int main() {
	CaseT  // 单测时注释掉该行
	solve();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值