【LightOJ 1274】Beating the Dataset(概率DP)

来源:互联网 发布:php spl 编辑:程序博客网 时间:2024/06/02 09:43

【LightOJ 1274】Beating the Dataset(概率DP)

题目大意:
一道题目有多个输出文件。
每个文件有一个输出,”YES”或”NO”
现在直接提交答案,从”YES”开始,如果与后台答案不同时,下一次输出”NO”,以此类推,如果相同则接着输出上一次的答案。

给出n,表示后台n个输出,s表示输出文件的总大小,一个”YES”占3Byte
一个”NO”占2Byte

问判完最后一个输出后,错误的组数的期望。

初步思路:
dp[i][0]表示当前是第i字节,并且下一步要输出YES
dp[i][1]表示当前是第i字节,并且下一步要输出NO
后来发现输出爆炸,原因是这样来做,固定的s最终的结果会对应多种n,但固定n和s后,YES和NO的数量就固定了。

对啊!YES和NO固定的。思路2:
dp[i][j][0]表示i个YES j个NO,下一步输出YES
dp[i][j][1]表示i个YES j个NO,下一步输出NO
开不下。然后想到用时间换空间,但是这样时间也已经很爆炸了!

可能最近比较频繁做类似的题,想到边遍历边转移。也就是把一维状态在for循环中表现出来。
从1到n遍历,表示当前剩下i个文件没评测。
第二层循环YES的个数,表示剩下j个文件是YES
这不就是滚动数组吗!

然后转移搞一下就出来了
代码如下:

#include <iostream>#include <cmath>#include <cstdlib>#include <cstdio>#include <cstring>using namespace std;const int msz = 5555;double dp[msz][2];int main(){    int t,n,s;    scanf("%d",&t);    for(int z = 1; z <= t; ++z)    {        scanf("%d%d",&n,&s);        //Num of "YES"        int a = s-2*n;        memset(dp,0,sizeof(dp));        for(int i = 1; i <= n; ++i)        {            int p = i;            //printf("%d:\n",i);            for(int j = a; j >= 0; --j)            {                //i is "NO"                if(j < i)                {                    dp[j][0] = (dp[j][1]+1)*(i-j)/p;                    dp[j][1] = dp[j][1]*(i-j)/p;                }                else dp[j][1] = dp[j][0] = 0;                //i is "YES"                if(j >= 1 && j <= i)                {                    dp[j][0] += dp[j-1][0]*j/p;                    dp[j][1] += (dp[j-1][0]+1)*j/p;                }                //printf("prt:YES useYES:%d %f\n",j,dp[j][0]);                //printf("prt:NO useYES:%d %f\n",j,dp[j][1]);            }        }        printf("Case %d: %.11f\n",z,dp[a][0]);    }    return 0;}
0 0
原创粉丝点击