Foreign Postcards Gym

来源:互联网 发布:怎么看待网络暴力 编辑:程序博客网 时间:2024/06/05 20:44

题目链接:https://vjudge.net/problem/Gym-101190F

题意:一开始共有n个卡片,C代表摆放正确,W代表摆放错误,每次可以选取前k张卡片,如果这k张卡片中的第一张是W,则将这k张卡片全部翻转后放在桌面上(翻转即C变W,W变C),如果第一张是C则不进行任何操作直接将这k张卡片放在桌面上,然后再在剩下的卡片中重复进行上述操作,直至所有卡片都放在桌面上了。求最终桌面上W个数的期望值。

思路:场上看出来是概率DP,但是不会推状态就去搞模拟了,看了题解的状态后自己推公式也能推出来,但是最难得还是如何找状态,DP学习很难一蹴而就,得经常联系培养思维才行。设P[i]为第i张牌作为k张牌中的第一张牌的可能性,p[0] = 1(第一张牌在第一次操作时一定是首张牌),p[i] = 1.0 / (n - i + 1.0),i >= 1。这个仔细退一下不难发现,我推到i=3发现的规律。设dp[i][0]代表第i张牌不翻转的概率,dp[i][1]代表第i张牌翻转的概率。最后对所有卡片为W的概率求和即可。如果s[i] == 'C', ans += dp[i][1](第i张卡片翻转后才能变成W), 否则ans += dp[i][0](第i张卡片起初就是W,故不需要翻转)。推状态转移方程时,只要考虑i和i-1即可。每张牌要么翻转要么不翻转,故dp[i][0] + dp[i][1] = 1,本来以为求出dp[i][0],直接用1-dp[i][0]求得dp[i][1]即可,但是可能是精度卡的太严的原因吧会Wrong Answer in Test 27,后来用状态转移公式求dp[i][1],就过了。看了RX的代码更加神奇,他写的用if else过不了,用三目运算符就能够。个人觉得是精度问题,但是我实在看不出他的两种写法有什么区别。RX的博客:http://blog.csdn.net/kim0403/article/details/77685142 dp状态转移方程详细见代码。

代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<sstream>#include<deque>#include<stack>#include<set>#include<map>using namespace std;typedef long long ll;typedef unsigned long long ull;const double eps = 1e-9;const int  maxn = 1e6 + 20;const int  maxt = 300 + 10;const int mod = 10;const int dx[] = {1, -1, 0, 0};const int dy[] = {0, 0, -1, 1};const int Dis[] = {-1, 1, -5, 5};const double inf = 0x3f3f3f3f;const int MOD = 1000;const double PI = acos(-1.0);int n, m, k;char s[maxn];double dp[maxn][2];double p[maxn];int main(){    freopen("foreign.in", "r", stdin);    freopen("foreign.out", "w", stdout);    scanf("%s", s);    int len = strlen(s);    p[0] = 1.0;//第一张牌一定会是第一次取的k张牌中的首张牌    for(int i = 1; i < len; ++i) p[i] = 1.0 / (len - i + 1.0);//第i张牌是取出的k张牌的首张的概率    if(s[0] == 'W'){//先确定好第一张牌翻转概率        dp[0][0] = 0.0; dp[0][1] = 1.0;    }    else{        dp[0][0] = 1.0; dp[0][1] = 0.0;    }    double ans = 0.0;    for(int i = 1; i < len; ++i){        if(s[i] == 'C'){            dp[i][0] = p[i] + (1 - p[i]) * dp[i - 1][0];//i为第一张时不用翻转,i不是第一张第i-1张不用翻转时第i张也一定不用翻转            dp[i][1] = (1 - p[i]) * dp[i - 1][1];//i不是第一张第i-1张翻转时第i张也一定也跟着翻转//            dp[i][1] = 1.0 - dp[i][0];//这样求dp[i][1]会WA in Test 27            ans += dp[i][1];        }        else{            dp[i][0] = (1 - p[i]) * dp[i - 1][0];//i不是第一张第i-1张不用翻转时第i张也一定不用翻转            dp[i][1] = p[i] + (1 - p[i]) * dp[i - 1][1];//i为第一张时会翻转,i不是第一张第i-1张翻转时第i张也一定跟着翻转//            dp[i][1] = 1.0 - dp[i][0];            ans += dp[i][0];        }    }    printf("%.10f\n", ans);    return 0;}


原创粉丝点击