...好像题有点古老了 bzoj那道都不见了 都没法去交了 只好贴别人的代码了 大佬博客
Codeforces280c
题意
给出一棵含n个白点的有根树,每次随机选择一个还没有被染黑的节点,将这个节点和这个节点子树中的所有点染黑.
问期望操作多少次后所有点都被染黑.
N<=100000
思路
只有删除掉1号点才算结束。考虑一个点被选中删除的概率。 ,dep[i]表示i点的深度,其中1号根节点的深度为1.
只有他到根路径上的点都没有被选中,他才能被选中。
期望步数实际上就是选中的点的期望次数。
所以
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=1e5+10;
int head[maxn],val[maxn*2],nxt[maxn*2];
int tot;
double ans=0;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void add(int u,int v)
{
val[tot]=v;
nxt[tot]=head[u];
head[u]=tot++;
}
void dfs(int u,int f,int step)
{
ans+=1.0/step;
for(int i=head[u];i+1;i=nxt[i])
{
int v=val[i];
if(v==f)
continue;
dfs(v,u,step+1);
}
}
int main()
{
init();
int n;
cin>>n;
for(int i=1;i>a>>b;
add(a,b);
add(b,a);
}
dfs(1,1,1);
printf("%.20lf\n",ans);
return 0;
}
bzoj2134
题意
给出n道题目,每道题目有a[i]个选项,有一个人知道所有题目的正确选项,但是他把答案全部写在了第i+1的题目上(第n个题目的答案写在了第1个题目上),求出这个人做对题目的期望。
思路
首先对于a[i-1]和a[i]而言,假设要答对第i道题的话,那么概率就是min(a[i-1],a[i])/(a[i-1]*a[i])(a[i-1]*a[i]为方案总数)
但是a[i-1]*a[i]会暴int,所以我们简化为1.0/max(a[t],a[i]),就可以了
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
int a[11000000];
double f[11000000];
int main()
{
int n,A,B,C;
scanf("%d%d%d%d%d",&n,&A,&B,&C,&a[1]);
for(int i=2;i<=n;i++) a[i]=((LL)a[i-1]*A+B)%100000001;
for(int i=1;i<=n;i++) a[i]=a[i]%C+1;
for(int i=1;i<=n;i++)
{
int t=i-1;if(t==0) t=n;
f[i]=f[t]+1.0/max(a[t],a[i]);
}
printf("%.3lf\n",f[n]);
return 0;
}
bzoj3036绿豆蛙的归宿
Description
随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿。
给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度。绿豆蛙从起点出发,走向终点。
到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。
现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?
Input
第一行: 两个整数 N M,代表图中有N个点、M条边
第二行到第 1+M 行: 每行3个整数 a b c,代表从a到b有一条长度为c的有向边
Output
从起点到终点路径总长度的期望值,四舍五入保留两位小数。
Sample Input
4 4
1 2 1
1 3 2
2 3 3
3 4 4
Sample Output
7.00
HINT
对于100%的数据 N<=100000,M<=2*N
思路
由期望的线性性可得:经过路径期望总长度=sigma{每条边期望经过次数*边权}
因为是有向无环图,所以 每条边的期望经过次数=该边起点的期望经过次数*从该起点出发经过该路径的概率。
于是问题转成了求每个点的期望经过次数。很显然,每个点的期望经过次数=sigma{入边i的期望经过次数}
于是发现边与点的期望值是相辅相成的关系,由于是有向无环图,所以拓扑排序就可以了
#include
#include
#include
#include
using namespace std;
const int N=100000+5;
int n,m,in[N],out[N];
int head[N],end[N*2],len[N*2],nxt[N*2],hh=0;
queue q;
double p[N],ans=0;
void adde(int a,int b,int c){
hh++;
end[hh]=b;
len[hh]=c;
nxt[hh]=head[a];
head[a]=hh;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
adde(a,b,c);
in[b]++,out[a]++;
}
q.push(1);
p[1]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=nxt[i]){
int v=end[i];
ans+=p[u]/out[u]*len[i];
p[v]+=p[u]/out[u];
in[v]--;
if(in[v]==0){
q.push(v);
}
}
}
printf("%.2lf",ans);
return 0;
}