版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/84680448
今天讲了讲数学,期望这做了四道题,一块写个博客记一下
CF540D Bad Luck Island
容易想到设
表示剩下
个
,
个
,
个
时候的概率,然后枚举遇见的是哪两种人,算一下概率就好了,但算的时候注意不能直接算,因为同种的人不能遇见,所以要减掉
#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
因为对于一个节点
,它父亲的子节点在它前面的概率都是
,所以就可以预处理节点
,
#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
枚举还剩下的鱼的集合,然后枚举那两个鱼遇见,算每条鱼被吃掉的概率
#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
一个有意思的题
注意到除了给定的这个人,其他人的水平都是一样的,这意味着我们可以先算出一个人的,再 就是其他所有人的,所以就可以设 表示前 场比赛得到了 分的概率,这样给定人的排名期望就是分数比他小的那些值的和再
滚动数组优化一下空间,然后记一个前缀和优化时间复杂度
#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);
}
一些小技巧: