ybtoj NOIP2020 模拟赛 A 组 Day10 偷学计划
Description–
已知有 n n n 份作业,老师会有 p i p_i pi 的概率给他第 i i i 种作业。做完第 i i i 份作业,他的愉悦度就会增加 w i w_i wi ,问他能够获得的最大愉悦度以及要作业的期望次数
Input–
第一行一个整数
n
n
n ,表示有
n
n
n 份作业
接下来
n
n
n 行,每行一个实数
p
i
p_i
pi 和正整数
w
i
w_i
wi,表示第
i
i
i 份作业出现的概率和完成可获得的愉悦度
Output–
第一行一个整数表示可以获得的最大喜悦值
第二行一个实数表示获得这个喜悦值的期望购买次数,保留
3
3
3 位小数
Sample Input–
3
0.1 2
0.2 5
0.3 7
Sample Output–
14
12.167
说明–
对于
10
%
10\%
10% 的数据,
n
=
1
n = 1
n=1
对于
30
%
30\%
30% 的数据,
n
≤
5
n \leq 5
n≤5
对于
100
%
100\%
100% 的数据,
1
<
n
≤
20
1 < n \leq 20
1<n≤20,
0
<
w
i
≤
1
0
5
0 < w_i \leq 10^5
0<wi≤105,
0
<
p
i
≤
1
0 < p_i \leq 1
0<pi≤1,
0
<
∑
p
i
≤
1
0 < ∑ p_i \leq 1
0<∑pi≤1
解题思路–
首先可以获得的最大喜悦值为
∑
w
i
∑ w_i
∑wi
然后用状压表示
f
[
i
]
f[i]
f[i] 为做过的作业状态为
i
i
i 的期望次数
则
即
代码–
#include <iostream>
#include <cstdio>
using namespace std;
int n, w;
double cs, p[25], f[1100000];
long long sum;
int main()
{
freopen("plan.in", "r", stdin);
freopen("plan.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%lf%d", &p[i], &w);
sum += w;
}
printf("%lld\n", sum);
for (int i = 1; i < (1 << n); ++i)
{
f[i] = 1, cs = 0;
for (int j = 0; j < n; ++j)
if ((i >> j) & 1)
{
f[i] += f[i - (1 << j)] * p[j + 1];
cs += p[j + 1];
}
f[i] /= cs;
}
printf("%.3lf", f[(1 << n) - 1]);
return 0;
}