[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 61∼6的六面骰子,其中前两人得到的数字分别为a,b (1≤a,b≤b)a,b\ \ (1\leq a,b\leq b)a,b (1≤a,b≤b).若第三个人得到的数字不小于另外两个人得到的数字,则他胜.求他胜的概率,输出既约分数的形式.
思路
显然ans=6−max{a,b}+16ans=\dfrac{6-\max\{a,b\}+1}{6}ans=66−max{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 m1∼m的mmm个专业,其中人数分别为s1,⋯ ,sns_1,\cdots,s_ns1,⋯,sn,小明来自专业h (1≤h≤m)h\ \ (1\leq h\leq m)h (1≤h≤m).求小明至少有一个同专业的队友的概率,误差不超过1e−61\mathrm{e}-61e−6.若组成队伍的人数不足,输出−1-1−1.
第一行输入三个整数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 (1≤n≤100,1≤m≤1000,1≤h≤m).第二行输入mmm个整数s1,⋯ ,sn (1≤si≤100)s_1,\cdots,s_n\ \ (1\leq s_i\leq 100)s1,⋯,sn (1≤si≤100),其中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}ba和cd\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 (1≤a,b,c,d≤1000,0<ba,dc<1).
思路
两人各打一次为一轮,则一轮中两人都没射中的概率为q=(1−ab)(1−cd)q=\left(1-\dfrac{a}{b}\right)\left(1-\dfrac{c}{d}\right)q=(1−ba)(1−dc).设A获胜前经过了nnn轮,则ans=p∑i=0n−1qi\displaystyle ans=p\sum_{i=0}^{n-1} q^ians=pi=0∑n−1qi.令n→∞n\rightarrow\inftyn→∞得ans=p1−qans=\dfrac{p}{1-q}ans=1−qp.
代码
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-10−1序列,其中000表示好日子,111表示坏日子,???表示有ppp的概率为坏日子,有(1−p)(1-p)(1−p)的概率为好日子.求坏日子的期望天数.
思路
直接计算即可.
本题是节日题,要求用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 (1≤m≤1e5)个面的骰子,其中每个面上写有数字1∼m1\sim m1∼m.求投掷n (1≤n≤1e5)n\ \ (1\leq n\leq1\mathrm{e}5)n (1≤n≤1e5)次后能得到的最大值的期望.
思路
即给定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(X≤k)−P(X≤k−1).
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=1∑mi⋅P(X=i)=i=1∑mi⋅[P(X≤i)−P(X≤i−1)]=i=1∑mi⋅[(mi)n−(mi−1)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}-91e−9.
第一行输入一个只包含字符’+‘和’-‘的字符串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=target−last.
①disdisdis与unknownunknownunknown奇偶性不同或unknown<abs(dis)unknown<abs(dis)unknown<abs(dis)时无解,概率为000.
②设从lastlastlast走到targettargettarget所需的步数为needneedneed,则need−(unknown−need)=∣dis∣need-(unknown-need)=|dis|need−(unknown−need)=∣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[i−1][j−1]∗0.5+dp[i−1][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 n1∼n的nnn个节点的、边长都为111的树.某人从节点111出发,每次等概率地选择一个与当前节点相邻的且之前未经过的节点,行走到该节点,若不存在这样的节点,则结束.求经过的路径长度的期望,误差不超过1e−61\mathrm{e}-61e−6.
第一行输入一个整数n (1≤n≤1e5)n\ \ (1\leq n\leq 1\mathrm{e}5)n (1≤n≤1e5).接下来(n−1)(n-1)(n−1)行每行输入两个整数u,v (1≤u,v≤n,u≤v)u,v\ \ (1\leq u,v\leq n,u\leq v)u,v (1≤u,v≤n,u≤v),表示节点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]=v∈sonu∑dp[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,len−1],将sss循环左移kkk位,即变为t=sk+1⋯sns1⋯skt=s_{k+1}\cdots s_n s_1\cdots s_kt=sk+1⋯sns1⋯sk.初始时给定ttt的首字符,你可询问ttt串的某位置的另一字符,问能唯一确定kkk的概率,误差不超过1e−61\mathrm{e}-61e−6.注意可能能确定但非一定能唯一确定视为不能确定.
第一行输入一个长度不超过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 n1∼n的nnn张卡片,每张卡片上分别有一个红色数码r1,⋯ ,rnr_1,\cdots,r_nr1,⋯,rn和蓝色数码b1,⋯ ,bnb_1,\cdots,b_nb1,⋯,bn.现将所有卡片排序,等概率地对应一个1∼n1\sim n1∼n的全排列,后依次读出每张卡片上的红色数码得到数字RRR,依次读出每张卡片上的蓝色数码得到数字BBB.若R>BR>BR>B则红色胜出;若R<BR<BR<B则蓝色胜出;否则平局.若红色胜出的概率严格大,输出"RED";若蓝色胜出的概率严格大,输出"BLUE";否则输出"EQUAL".
有t (1≤t≤100)t\ \ (1\leq t\leq 100)t (1≤t≤100)组测试数据.每组测试数据第一行输入一个整数n (1≤n≤1000)n\ \ (1\leq n\leq 1000)n (1≤n≤1000).第二行输入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]的下标的个数cnt1cnt1cnt1和cnt2cnt2cnt2.
①若最终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 n1∼n的排列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}-61e−6.
有t (1≤t≤100)t\ \ (1\leq t\leq 100)t (1≤t≤100)组测试数据.每组测试数据第一行输入两个整数n,m (1≤n,m≤1e5)n,m\ \ (1\leq n,m\leq 1\mathrm{e}5)n,m (1≤n,m≤1e5).第二行输入一个1∼n1\sim n1∼n的排列a1,⋯ ,ana_1,\cdots,a_na1,⋯,an.接下来mmm行每行输入一个整数r (1≤r≤n)r\ \ (1\leq r\leq n)r (1≤r≤n)和一个实数p (0≤p≤1)p\ \ (0\leq p\leq 1)p (0≤p≤1),表示一个操作.数据保证所有测试数据的nnn之和、mmm之和都不超过1e51\mathrm{e}51e5.
思路
记最大的 s.t. ai!=i\ s.t.\ a_i!=i s.t. ai!=i的下标iii为pospospos.显然答案与r<posr<posr<pos的操作无关,则只需考察r≥posr\geq posr≥pos的操作,将它们排序失败的概率(1−p)(1-p)(1−p)相乘后,用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();
}

602

被折叠的 条评论
为什么被折叠?



