昨天从金华回来,成绩不理想,但是也没办法,自己的问题,想知道比赛详情的请戳http://bbs.whu.edu.cn/wForum/disparticle.php?boardName=ACM_ICPC&ID=1105535232&pos=11
今年的比赛算是结束了,于是心想现在还是本着学习的态度,重新开始学习新的知识,于是想着就从DP开始吧。不知怎么地,搜到了一道概率DP的题目,就开始研究。
如果要学习概率DP,可以从LIGHT OJ的1027开始,再到POJ 2096,LIGHT OJ 1030,1038。差不多就有个入门级的了解了。
ACM比赛中,概率DP一般来说都是求数学期望。
对于独立事件之间的期望,可以注意到,如果每次求一次子概率,又碰到原来的那个情况,那么数学期望也是一样的,于是就可以列出一个最基本的一元一次方程,求解即可。LIGHT OJ 1027和LIGHT OJ 1038都是练习这种思维的好题。
对于其他类型的概率DP,我们可以试着从后面往前面推,什么意思呢?就是我们可以以dp[n]为起点,然后一直往前面推,找结论。具体的问题还得具体分析,LIGHT OJ 1030和POJ 2096都是这方面的好题。
当然,练习概率DP首先要对概率论的知识有所了解,否则肯定没法做题。
下面贴一个Light OJ 1038的代码,供参考:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 111111;
double dp[maxn];
void calc_p()
{
dp[2] = 2.0, dp[3] = 2.0;
for(int i = 4; i <= 100000; i ++)
{
dp[i] = 0.0;
for(int j = 2; j * j <= i; j ++)
{
if(i % j == 0)
break;
if((j + 1) * (j + 1) > i) // if i is a prime the its val is 2
dp[i] = 2.0;
}
}
}
double calc_val(int n)
{
double sm = 2.0;
int cnt = 2;
for(int i = 2; i * i <= n; i ++)
{
if(n % i == 0)
{
cnt ++;
if(dp[i])
sm += (1 + dp[i]);
else
sm += (1 + calc_val(i));
if(i * i != n)
{
cnt ++;
int j = n / i;
if(dp[j])
sm += (1 + dp[j]);
else
sm += (1 + calc_val(j));
}
}
}
dp[n] = sm / (cnt - 1);
return dp[n];
}
int main()
{
int cse, t = 1, n;
calc_p();
dp[1] = 0.0;
scanf("%d", &cse);
while(cse --)
{
scanf("%d", &n);
printf("Case %d: ", t ++);
if(n == 1)
{
printf("0.0000000000\n");
continue;
}
if(dp[n])
printf("%.10lf\n", dp[n]);
else
printf("%.10lf\n", calc_val(n));
}
}