概率
随机事件
1.可以重复做
2.可以枚举出所有可能结果
对于每一个可能结果,我们称为一个样本点
所有样本点的集合,我们称为样本空间
3.不可预料出现哪一个结果
概率的表示
A随机事件出现的概率:P(A)
B随机事件出现的概率:P(B)
A,B均出现的概率:P(AB) [积事件]
A,B至少有一个出现的概率:P(A+B)[和事件]
排列组合
排列:考虑顺序的选取
组合:不考虑顺序的选取
随机变量
将随机事件映射成函数
离散型:随机变量取值有限
连续型:随机变量取值无限
期望
expectation
例题:
FAVDICE - Favorite Dice
设dp[i]表示已经掷到了i个不同的面,还需掷多少次的期望
所求即dp[0]
那么对于dp[i]是怎么转移的呢
至于能不能写出正推的状态转移方程
答案是否定的
qaq
One Person Game
这里我们很容易设出这样的状态
dp[i]表示已有i个点数,达到大于n个点数的期望次数
但由于dp[i+j+k+l]已知,dp[0]未知
我们无法直接递推这个式子得到答案
其实对于这样的n+1个方程,我们可以用高斯消元搞定
但数据范围不允许n^3的复杂度
我们应另求出路
搞定qaq
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=505;
double x[maxn],y[maxn];
int read(){
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*y;
}
int main(){
int t;
t=read();
while(t--){
int n,k1,k2,k3,a,b,c;
n=read();
k1=read();k2=read();k3=read();
a=read();b=read();c=read();
double p=1.0/k1/k2/k3;
x[n+1]=0;
y[n+1]=0;
for(int i=n;i>=0;i--){
x[i]=p;
y[i]=1;
for(int j=1;j<=k1;j++){
for(int k=1;k<=k2;k++){
for(int l=1;l<=k3;l++){
if(j==a&&k==b&&l==c)continue;
int v=i+j+k+l;
if(v>n)v=n+1;
x[i]+=p*x[v];
y[i]+=p*y[v];
}
}
}
}
printf("%.15f\n",y[0]/(1-x[0]));
}
return 0;
}
Maze
容易想到的期望dp状态
由于j为所有与i有直接边相连的节点
想到树形dp
将父节点与子节点分开计算
由于dp[1]未知
我们考虑采取上一题类似的方法
树形dp即可
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10005;
struct Edge{
int to;
int nxt;
}e[2*maxn];
int cnt;
int head[maxn];
double p1[maxn],p2[maxn];
double a[maxn],b[maxn],c[maxn];
int read(){
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*y;
}
void add(int u,int v){
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
return ;
}
void dfs(int x,int fa){
int edge=1;
if(!fa)edge=0;
double suma=0,sumb=0,sumc=0;
for(int i=head[x];i!=-1;i=e[i].nxt){
int tmp=e[i].to;
if(tmp==fa)continue;
dfs(tmp,x);
edge++;
suma+=a[tmp];
sumb+=b[tmp];
sumc+=c[tmp];
}
double p=(1-p1[x]-p2[x])*1.0/edge,val=1-p*sumb;
a[x]=(p1[x]+p*suma)*1.0/val;
b[x]=p*1.0/val;
c[x]=(p*sumc+1-p1[x]-p2[x])/val;
return ;
}
int main(){
int t,cas=0;
t=read();
while(t--){
int n;
n=read();
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){
int x,y;
x=read();y=read();
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++){
int x,y;
x=read();y=read();
p1[i]=x*1.0/100;
p2[i]=y*1.0/100;
}
dfs(1,0);
cas++;
if(a[1]==1)printf("Case %d: impossible\n",cas);
else printf("Case %d: %.6f\n",cas,c[1]/(1-a[1]));
}
return 0;
}#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10005;
struct Edge{
int to;
int nxt;
}e[2*maxn];
int cnt;
int head[maxn];
double p1[maxn],p2[maxn];
double a[maxn],b[maxn],c[maxn];
int read(){
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*y;
}
void add(int u,int v){
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
return ;
}
void dfs(int x,int fa){
int edge=1;
if(!fa)edge=0;
double suma=0,sumb=0,sumc=0;
for(int i=head[x];i!=-1;i=e[i].nxt){
int tmp=e[i].to;
if(tmp==fa)continue;
dfs(tmp,x);
edge++;
suma+=a[tmp];
sumb+=b[tmp];
sumc+=c[tmp];
}
double p=(1-p1[x]-p2[x])*1.0/edge,val=1-p*sumb;
a[x]=(p1[x]+p*suma)*1.0/val;
b[x]=p*1.0/val;
c[x]=(p*sumc+1-p1[x]-p2[x])/val;
return ;
}
int main(){
int t,cas=0;
t=read();
while(t--){
int n;
n=read();
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){
int x,y;
x=read();y=read();
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++){
int x,y;
x=read();y=read();
p1[i]=x*1.0/100;
p2[i]=y*1.0/100;
}
dfs(1,0);
cas++;
if(a[1]==1)printf("Case %d: impossible\n",cas);
else printf("Case %d: %.6f\n",cas,c[1]/(1-a[1]));
}
return 0;
}