SDUT 2021 Autumn Team Contest 10th(补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2021 Autumn Team Contest 10th(补题)相关的知识,希望对你有一定的参考价值。
C - Justice
题目链接: link.
题意:
给 n n n个数,现在每个数都表示为 1 2 a i \\frac{1}{2^{a_i}} 2ai1,现在问你能否把 n n n个数拆分成2组,每组数的和必须 > = >= >= 1 2 \\frac{1}{2} 21,问能否把 n n n个数分成 2 2 2组满足题意,如果可以,并把划分2组的方案输出,用0和1来代表两个组
思路:
1 2 i \\frac{1}{2^i} 2i1✖ 1 2 i \\frac{1}{2^i} 2i1= 1 2 i − 1 \\frac{1}{2^{i-1}} 2i−11,也就是两个相同的数,可以合并成一个大数。此时划分方案,就是每个组里面至少有 1 1 1个 1 1 1,也就是整个数组里面通过合并,是否至少有2个1,1可以是合并出来的,也可以是原有的,如果可以就是yes,否则就是no,再通过数组发现, n n n最大时1e5,在只有 n n n个数的情况下, a i a_i ai最小是1e5-1,也就是样例为1,2,3,4,……1e5-1,1e5-1,通过合并最后也是合法的,此时发现最大的数能用桶来存下,那么直接开个桶来记录每个数的个数,对于>1e5的数,就算有再多也对答案没影响,所以不做处理。通过不断合并看最后1的个数是否 > = 2 >=2 >=2,如果是,那就开始考虑方案,方案的话,就枚举对于当前这个数,需要多少个这样的数才能满足方案,记录下,这个数需要的个数,最后被标记个数的数为一组,剩下的数为一组。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5;
int a[N + 10], cnt[N + 10], ans[N + 10];
int n;
ll qmi(ll a, ll k) {
ll res = 1;
while (k) {
if (k & 1) res = res * a;
k >>= 1;
a = a * a;
}
return res;
}
void init() {
memset(ans, 0, sizeof(ans));
memset(cnt, 0, sizeof(cnt));
}
int main() {
int T, idx = 1;
scanf("%d", &T);
while (T--) {
init();
scanf("%d", &n);
int maxv = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
if (a[i] > N) continue;
cnt[a[i]]++;
maxv = max(maxv, a[i]);
}
ll p = 0;
//计算1的个数
for (int i = maxv; i > 1; i--) {
p = (p + cnt[i]) / 2;
}
//1的个数>=2满足题意
if (cnt[1] + p >= 2) {
printf("Case %d: YES\\n", idx++);
ll now = 0;
//枚举当前这个数,在一组中需要多少个
for (int i = 1; i <= maxv; i++) {
ll temp = qmi(2, i - 1);
if (cnt[i] + now >= temp) {
ans[i] = temp - now;
break;
} else {
now = (now + cnt[i]) * 2;
ans[i] = cnt[i];
}
}
for (int i = 0; i < n; i++) {
if (a[i] > N)
printf("0");
else {
if (ans[a[i]]) {
printf("1");
ans[a[i]]--;
} else
printf("0");
}
}
printf("\\n");
} else
printf("Case %d: NO\\n", idx++);
}
return 0;
}
D - The Moon
题目链接: link.
题意:
有一个测试游戏的任务是拿到包裹,初始拿到包裹的概率是q=2% ,玩一局游戏获胜的概率是p,如果游戏获胜那就可以尝试拿包裹,成功拿包裹的概率是q,如果拿到就结束,没拿到就使得q=q+2%,并继续游戏。如果游戏失败,那就使q=q+1.5%,问拿到包裹的期望游戏回合数。
思路:
定义
f
(
i
)
f(i)
f(i)为概率是
i
i
i的情况下,拿到包裹的期望回合数。
f
(
i
)
f(i)
f(i)=
p
∗
(
i
+
(
1
−
i
)
∗
[
f
(
m
i
n
(
100
,
i
+
2
)
+
1
]
)
+
(
1
−
p
)
∗
(
f
(
m
i
n
(
100
,
i
+
1.5
)
+
1
)
p*(i+(1-i)*[f(min(100,i+2)+1])+(1-p)*(f(min(100,i+1.5)+1)
p∗(i+(1−i)∗[f(min(100,i+2)+1])+(1−p)∗(f(min(100,i+1.5)+1)
代表含义就是
f
(
i
)
f(i)
f(i)=当前获胜且拿到包裹的期望+获胜当前没拿到包裹的期望+没获胜后面拿到包裹的期望
为了防止1.5无法无法用整数表示所以,把所有数✖2
一开始f(200)即拿到包裹的概率是100%的情况下,能拿到包裹的期望就是
1
p
\\frac{1}{p}
p1,这就是经典硬币游戏的结论,引用过来就是,玩一个概率是p的游戏,赢了就结束,输了继续,结束的期望值是
1
p
\\frac{1}{p}
p1
取
m
i
n
min
min是为了防止越界
#include <bits/stdc++.h>
using namespace std;
const int N = 2000;
double f[N];
int main() {
int T;
scanf("%d", &T);
int idx = 1;
while (T--) {
memset(f, 0, sizeof(f));
printf("Case %d: ", idx++);
double p;
scanf("%lf", &p);
p = p / 100.0;
f[200] = 1.0 / p;
for (int i = 199; i >= 4; i--) {
double x = i / 200.0;
f[i] = p * (x + (1 - x) * (f[min(i + 4, 200)] + 1)) + (1 - p) * (f[min(i + 3, 200)] + 1);
}
printf("%.10lf\\n", f[4]);
}
return 0;
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于SDUT 2021 Autumn Team Contest 10th(补题)的主要内容,如果未能解决你的问题,请参考以下文章
SDUT 2021 summer team contest 1st(for 20)(补题)
SDUT 2022 Winter Team Contest - 1
SDUT 2022 Winter Team Contest - 1
SDUT 2022 Winter Team Contest - 1