今天讲了讲数学,期望这做了四道题,一块写个博客记一下
CF540D Bad Luck Island
容易想到设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示剩下
i
i
i个
r
r
r,
j
j
j个
s
s
s,
k
k
k个
p
p
p时候的概率,然后枚举遇见的是哪两种人,算一下概率就好了,但算的时候注意不能直接算,因为同种的人不能遇见,所以要减掉
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 105
using namespace std;
int r,s,p;
double f[maxn][maxn][maxn],ans[3];
int main(){
scanf("%d%d%d",&r,&s,&p);
f[r][s][p]=1;
for(int i=r;i>=0;i--)
for(int j=s;j>=0;j--)
for(int k=p;k>=0;k--){
if(j && i)
f[i][j-1][k]+=f[i][j][k]*2*i*j/(double)((i+j+k)*(i+j+k-1)-i*(i-1)-j*(j-1)-k*(k-1));
if(k && j)
f[i][j][k-1]+=f[i][j][k]*2*j*k/(double)((i+j+k)*(i+j+k-1)-i*(i-1)-j*(j-1)-k*(k-1));
if(i && k)
f[i-1][j][k]+=f[i][j][k]*2*i*k/(double)((i+j+k)*(i+j+k-1)-i*(i-1)-j*(j-1)-k*(k-1));
}
for(int i=r;i>=0;i--) ans[0]+=f[i][0][0];
for(int i=s;i>=0;i--) ans[1]+=f[0][i][0];
for(int i=p;i>=0;i--) ans[2]+=f[0][0][i];
printf("%.12lf %.12lf %.12lf\n",ans[0],ans[1],ans[2]);
return 0;
}
CF696B Puzzles
因为对于一个节点
v
v
v,它父亲的子节点在它前面的概率都是
0.5
0.5
0.5,所以就可以预处理节点
s
i
z
siz
siz,
f
[
v
]
=
f
[
u
]
+
0.5
×
(
s
i
z
[
u
]
−
s
i
z
[
v
]
+
1
)
f[v]=f[u]+0.5\times (siz[u]-siz[v]+1)
f[v]=f[u]+0.5×(siz[u]−siz[v]+1)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100005
using namespace std;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int n,siz[N],cnt,to[N],nxt[N],head[N];
double f[N];
inline void add(int x,int y){
to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
}
void dfs1(int u,int fa){
siz[u]=1;
for(int i=head[u];i;i=nxt[i]){
int v=to[i]; if(v==fa)continue;
dfs1(v,u); siz[u]+=siz[v];
}
}
void dfs2(int u,int fa){
for(int i=head[u];i;i=nxt[i]){
int v=to[i]; if(v==fa)continue;
f[v]=f[u]+0.5*(siz[u]-siz[v]+1);
dfs2(v,u);
}
}
int main(){
n=rd();
for(int i=2;i<=n;i++){
int fa=rd(); add(fa,i);
}
f[1]=1;
dfs1(1,0); dfs2(1,0);
for(int i=1;i<=n;i++) printf("%.1lf ",f[i]);
return 0;
}
CF16E Fish
2
n
2^n
2n枚举还剩下的鱼的集合,然后枚举那两个鱼遇见,算每条鱼被吃掉的概率
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 20
using namespace std;
int n,ed,cnt[(1<<18)+5];
double a[maxn][maxn],f[(1<<18)+5];
inline int calc(int x){
int ret=0;
while(x){
if(x&1) ++ret; x>>=1;
} return ret;
}
int main(){
scanf("%d",&n); ed=1<<n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%lf",&a[i][j]);
for(int i=0;i<ed;i++) cnt[i]=calc(i);
f[ed-1]=1;
for(int i=ed-1;i>=1;i--)
for(int j=1;j<=n;j++)
if((1<<(j-1))&i)
for(int k=j+1;k<=n;k++)
if((1<<(k-1))&i){
f[i^(1<<(k-1))]+=f[i]*2*a[j][k]/cnt[i]/(cnt[i]-1);
f[i^(1<<(j-1))]+=f[i]*2*a[k][j]/cnt[i]/(cnt[i]-1);
}
for(int i=1;i<=n;i++)
printf("%.6lf ",f[1<<(i-1)]);
return 0;
}
CF601C Kleofáš and the n-thlon
一个有意思的题
注意到除了给定的这个人,其他人的水平都是一样的,这意味着我们可以先算出一个人的,再 × ( m − 1 ) \times (m-1) ×(m−1)就是其他所有人的,所以就可以设 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i场比赛得到了 j j j分的概率,这样给定人的排名期望就是分数比他小的那些值的和再 + 1 +1 +1
滚动数组优化一下空间,然后记一个前缀和优化时间复杂度
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 105
#define maxm 100005
using namespace std;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int n,m,sc,a[maxn];
double f[2][maxm],sum,ans;
int main(){
n=rd(); m=rd();
for(int i=1;i<=n;i++){
a[i]=rd(); sc+=a[i];
}
if(m==1) return puts("1"),0;
f[0][0]=1; int now=1;
for(int i=1;i<=n;i++){
sum=f[now^1][0]; memset(f[now],0,sizeof f[now]);
for(int j=1;j<=n*m;j++){
f[now][j]+=sum,sum+=f[now^1][j];
if(j>=a[i]) f[now][j]-=f[now^1][j-a[i]];
if(j>=m) sum-=f[now^1][j-m];
f[now][j]/=(m-1);
}
now^=1;
}
for(int i=n;i<sc;i++) ans+=f[now^1][i];
printf("%.15lf\n",ans*(m-1)+1.0);
}
一些小技巧:
1.
当
合
法
的
不
好
算
的
时
候
可
以
用
总
数
减
去
不
合
法
的
1.当合法的不好算的时候可以用总数减去不合法的
1.当合法的不好算的时候可以用总数减去不合法的
2.
当
一
些
东
西
的
性
质
相
同
时
可
以
先
算
出
某
一
个
,
再
用
它
去
算
所
有
的
2.当一些东西的性质相同时可以先算出某一个,再用它去算所有的
2.当一些东西的性质相同时可以先算出某一个,再用它去算所有的
3.
状
态
设
计
很
重
要
,
按
情
况
可
以
设
由
起
点
开
始
和
由
终
点
倒
推
,
一
般
是
哪
个
好
确
定
就
从
哪
个
开
始
3.状态设计很重要,按情况可以设由起点开始和由终点倒推,一般是哪个好确定就从哪个开始
3.状态设计很重要,按情况可以设由起点开始和由终点倒推,一般是哪个好确定就从哪个开始