DAGE(Big Brother)
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
Our famous “DAGE”, God Kufeng, likes killing monsters. However, killing monsters is a tiring job, and might do harm to DAGE’s health.
Now there are n monsters, each monster has a strength value. Let’s say, before killing a monster with strength X , DAGE has a health point(HP) as V , then after killing, DAGE’s HP will become
Vnew=V&X
Here &
means bitwise AND. For example,
5&4=4
,
5&2=0
.
At first, the health point(HP) of DAGE will be 2047 .
DAGE has a simple strategy, each time he just randomly choose a monster to kill, and kill that monster.
When DAGE’s HP becomes 0 , DAGE will feel tired and go home to sleep.
What is the expected number of monsters DAGE has killed when DAGE goes to bed? It is guaranteed that DAGE will go to bed at some moment.
Input
The first line contains a single number n , the number of the monsters. ( 1≤n≤50 )
The the second line comes with n numbers x1,x2,⋯,xn , those are the strenght value of each monster. (0≤xi≤2047) .
Output
Output a single number in a line, the expected number of monsters DAGE has killed when he goes to bed, rounded to 3 digits after decimal point.
Sample input and output
Sample Input | Sample Output |
---|---|
3 0 1 2 | 1.667 |
Source
解析
概率DP
dp[i][j]表示杀了 i 个怪还剩 j 滴血的概率。转移的时候有个问题,不知道哪些怪被杀过。(同一个怪不能杀两次)
其实我不用知道哪些怪死了(因为它们的概率会叠加),我只用知道那个时候死了多少个怪。(如果看不懂这句话可以忽略它,看代码就会明白的)
如果先前第a个怪被打过那么一定有x[a]&j==j
然而怪b满足x[b]&j==j却不一定说明怪b被打过
那么对于血量为 j 的时候,我统计一下哪些怪可能被杀过
for(int k=1;k<=N;k++)//血量为j时,最多可能打cnt个怪
if((x[k]&j)==j) cnt++;
从dp[i][j]转移到dp[i+1][j]的可能性是 (cnt-i)/(N-i)
不满足的 (x[k]&j)==j 的转移就是概率就是1/(N-i)
注意&的优先级比==低。还有题目要求的的期望是血为0的期望,杀完了N个怪,血还没用完是不回家的。
这份代码得到张倩如的指导。
#include<cstdio>
#include<algorithm>
using namespace std;
int N,x[55];
double dp[55][2048];
void readdata()
{
scanf("%d",&N);
for(int i=1;i<=N;i++) scanf("%d",&x[i]);
}
void dynamic_planning()
{
dp[0][2047]=1;
for(int i=0;i<N;i++)//有i个怪被杀了
for(int j=1;j<2048;j++)//当前血量
{
int cnt=0;
for(int k=1;k<=N;k++)//血量为j时,最多可能打cnt个怪
if((x[k]&j)==j) cnt++;
if(i>cnt) continue;//当前的j不可能杀i个怪
dp[i+1][j]+=(dp[i][j]*(cnt-i))/(N-i);//杀一个满足(x[k]&j)==j的怪
for(int k=1;k<=N;k++)
if((x[k]&j)!=j)//杀一个不满足(x[k]&j)==j的怪
dp[i+1][x[k]&j]+=dp[i][j]/(N-i);
}
}
void write()
{
double ans=0;
for(int i=1;i<=N;i++) ans+=dp[i][0]*i;
printf("%.3f",ans);
}
int main()
{
readdata();
dynamic_planning();
write();
while(1);
return 0;
}