文章目录
P1850 - [NOIP2016 提高组] 换教室
题目描述:
现在有 2 n 2n 2n 节课安排在 n n n 个时间段上。在第 i i i 个时间段上有内容相同的两节课分别在不同的教室 c i c_i ci 和 d i d_i di 在进行,牛牛每节课预先被安排在 c i c_i ci 教室上课。
现在可以提出换教室的申请,对于第 i i i 个时间段,有 k i k_i ki 的概率成功换课到 d i d_i di 教室,并且各个换教室的申请之间都是独立的。现在可以一次性至多提出 m m m 个申请(即代表着不能根据某节课是否申请更换成功而做其他决定)。
牛牛所在的学校有 v v v 个教室, e e e 条道路,经过每条道路需要花费对应的时间,并且保证可以从学校之间两两教室互通。现在要求知道申请哪几门课可以使得期望的花费时间最小,求出这个最小值
1 ≤ n ≤ 2000 , 0 ≤ m ≤ 2000 , 1 ≤ v ≤ 300 , 0 ≤ e ≤ 90000 1 \leq n \leq 2000,0 \leq m \leq 2000,1 \leq v \leq 300,0 \leq e \leq 90000 1≤n≤2000,0≤m≤2000,1≤v≤300,0≤e≤90000
solution:
期望基础题。
期望产生于从一个教室走到另一个教室的过程,根据期望的线性可加性,我们要求的期望就是相邻时段之间的期望之和,考虑用 dp 得到最优解,设 f i , j , 0 / 1 f_{i,j,0/1} fi,j,0/1 代表前 i i i 个时段用了 j j j 次换教室资格,并且第 i i i 个教室 没申请/申请了 换教室资格的最小期望(因为我们转移的时候要考虑前后两个时段的教室的具体位置)
转移方程比较直观,即对于所有 f i , j , 1 f_{i,j,1} fi,j,1 的情况,我们需要讨论它是否成功更换,详细见代码
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2077;
int n,m,v,e,c[maxn],d[maxn];
int g[305][305];
double k[maxn],f[maxn][maxn][2];
void floyd(){
for(int k=1;k<=v;k++){
for(int i=1;i<=v;i++){
for(int j=1;j<=v;j++) g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
}
}
int main(){
scanf("%d %d %d %d",&n,&m,&v,&e);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
memset(g,0x3f,sizeof g);
for(int i=1;i<=v;i++) g[i][i]=0;
int u,v,w;
for(int i=1;i<=e;i++){
scanf("%d %d %d",&u,&v,&w);
g[u][v]=g[v][u]=min(g[u][v],w);
}
floyd();
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=1e18;
}
f[1][0][0]=f[1][1][1]=0;
for(int i=2;i<=n;i++){
for(int j=0;j<=min(i,m);j++){
int c1=c[i],d1=d[i];
int c2=c[i-1],d2=d[i-1];
double w1=g[c1][c2];
double w2=g[c1][d2]*k[i-1]+g[c1][c2]*(1-k[i-1]);
double w3=g[d1][c2]*k[i]+g[c1][c2]*(1-k[i]);
double w4=g[d1][d2]*k[i]*k[i-1]+g[d1][c2]*k[i]*(1-k[i-1])+g[c1][d2]*(1-k[i])*k[i-1]+g[c1][c2]*(1-k[i])*(1-k[i-1]);
f[i][j][0]=min(f[i-1][j][0]+w1,f[i-1][j][1]+w2);
if(j) f[i][j][1]=min(f[i-1][j-1][0]+w3,f[i-1][j-1][1]+w4);
}
}
double ans=1e18;
for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2f\n",ans);
return 0;
}
P3802 - 小魔女帕琪
题目描述:
现在有 7 7 7 种属性的能量晶体,第 i i i 种晶体可以施放出属性为 i i i 的魔法,共有 a i a_i ai 个。每次施放魔法时,会等概率随机消耗一个现有的能量晶体,然后释放一个对应属性的魔法。如果连续施放的 7 7 7 个魔法的属性都各不相同,就能触发一次七重奏(无论这前 6 6 6 个魔法是否参与过之前的七重奏)。求触发七重奏的期望。
0 ≤ a i ≤ 1 0 9 , ∑ a i ≤ 1 e 9 0 \leq a_i \leq 10^9,\sum a_i \leq 1e9 0≤ai≤109,∑ai≤1e9
solution:
设 n = ∑ a i n = \sum a_i n=∑ai
首先题目问的实际上就是把这 n n n 个数放进一个空序列,然后总共 n − 6 n-6 n−6 个长度为 7 7 7 的连续序列中序列元素各不相同的期望,考虑计算每一段的期望然后相加。
对于第一段来说,其出现七重奏的概率是: 7 ! ⋅ ∏ i = 1 7 a i n ( n − 1 ) ( n − 2 ) ( n − 3 ) ( n − 4 ) ( n − 5 ) ( n − 6 ) \frac {7! \cdot\prod_{i=1}^7a_i} {n(n-1)(n-2)(n-3)(n-4)(n-5)(n-6)} n(n−1)(n−2)(n−3)(n−4)(n−5)(n−6)7!⋅∏i=17ai。( 7 7 7 种属性出现的顺序不同下的式子相同,所以乘以 7 ! 7! 7!)
接着考虑第二段,也就是第 8 8 8 次随机释放得到七重奏的概率。
首先要知道前后魔法施放不互相影响,相当于第一次胡乱用掉一个能量晶体后从头再来,也就是条件概率。
那么我们只需要考虑第一次用的是哪个晶体,对应的 a i a_i ai 减少 1 1 1,也就是这样的式子:
7 ! × a 1 n × a 1 − 1 n − 1 × a 2 n − 2 × . . . × a 7 n − 7 7! \times \frac {a_1} n \times \frac {a_1-1} {n-1} \times \frac {a_2} {n-2} \times...\times \frac {a_7} {n-7} 7!×na1×n−1a1−1×n−2a2×...×n−7a7 7 ! × a 2 n × a 2 − 1 n − 1 × a 1 n − 2 × . . . × a 7 n − 7 7! \times \frac {a_2} n \times \frac {a_2-1} {n-1} \times \frac {a_1} {n-2} \times...\times \frac {a_7} {n-7} 7!×na2×n−1a2−1×n−2a1×...×n−7a7 . . . ... ...
把他们相加,化简后发现和第一段的概率相同,最终我们推广到所有 n − 6 n-6 n−6 段,答案就是第一段的基础上在乘上 n − 6 n-6 n−6
7 ! × ( n − 6 ) × a 1 n × a 1 − 1 n − 1 × a 2 n − 2 × . . . × a 7 n − 7 7! \times (n-6) \times \frac {a_1} n \times \frac {a_1-1} {n-1} \times \frac {a_2} {n-2} \times...\times \frac {a_7} {n-7} 7!×(n−6)×na1×n−1a1−1×n−2a2×...×n−7a7
P4550 - 收集邮票
题目描述:
现在有 n n n 种不同的邮票,现在要购买邮票,其中第 i i i 次需要支付 i i i 元,并且等概率的得到 n n n 种邮票中的任意一种,即 1 n \frac 1 n n1 的概率吗,现在求收集所有邮票的期望花费。
solution:
购买价格与购买次数相关,我们先从购买次数入手,设 f i f_i fi 代表已经收集 i i i 张邮票,要取完剩下邮票的期望次数, 显然 f n = 0 f_n=0 fn=0。
分析一下,现在有 i n \frac i n ni 的概率取得重复的邮票,剩下概率得到新的邮票,那么转移方程: f i = i n ⋅ ( f i + 1 ) + n − i n ⋅ ( f i + 1 + 1 ) f_i=\frac i n \cdot (f_i+1)+\frac {n-i} n \cdot (f_{i+1}+1) fi=ni⋅(fi+1)+nn−i⋅(fi+1+1) 化简得到: f i = f i + 1 + n n − i f_i=f_{i+1}+\frac n {n-i} fi=fi+1+n−in
接着我们重新回到上面,求期望花费。设 g i g_i gi 代表已经收集 i i i 张邮票,要取完剩下邮票的期望花费, g n = 0 g_n=0 gn=0
接着 g i = i n ⋅ ( g i + f i + 1 ) + n − i n ⋅ ( g i + 1 + f i + 1 + 1 ) g_i=\frac i n \cdot (g_i+f_i+1) + \frac {n-i} n \cdot (g_{i+1}+f_{i+1}+1) gi=ni⋅(gi+fi+1)+nn−i⋅(gi+1+fi+1+1) 化简得到: g i = i n − i f i + g i + 1 + f i + 1 + n n − i g_i=\frac i {n-i} f_i+g_{i+1}+f_{i+1}+\frac n {n-i} gi=n−iifi+gi+1+fi+1+n−in
至于为什么是 f i + 1 f_i+1 fi+1 和 f i + 1 + 1 f_{i+1}+1 fi+1+1,因为我们是将后面取到的邮票费用+1,从后往前推,那么 f i f_i fi 的上一个状态是 f i + 1 f_{i+1} fi+1
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+50;
int n;
double f[maxn],g[maxn];
int main(){
scanf("%d",&n);
f[n]=g[n]=0;
for(int i=n-1;i>=0;i--){
f[i]=f[i+1]+n*1.0/(n-i);
g[i]=i*1.0/(n-i)*f[i]+g[i+1]+f[i+1]+n*1.0/(n-i);
}
printf("%.2f\n",g[0]);
return 0;
}
其实我们也可以不直接维护花费期望,我们如果知道收集所有邮票的期望次数 x x x,那么答案不就是每一步花费的和吗,也就是 ∑ i = 1 x = x 2 + x 2 \sum_{i=1}^x=\frac {x^2+x} 2 ∑i=1x=2x2+x,那么我们只需要维护期望次数的平方即可
Coupon collector’s problem
关于上一个问题,其涉及到一个经典问题,及有 n n n 个物品,每次花费 1 1 1 的代价等概率 1 n \frac 1 n n1 的得到任一物品,求得到所有物品的期望花费。
方法1: 参考上一题,我们设 已经…还需要… 状态倒推即可
方法2: 设 f i f_i fi 代表已经购买了 i i i 个物品的期望花费
考虑正推的期望,我们由 f i f_i fi 去推 f i + 1 f_{i+1} fi+1,那么当前已经有了 i i i 个物品,有 i n \frac i n ni 的概率重复得到已经有的物品
下一次得到不同物品的概率为 n − i n \frac {n-i} n nn−i,下两次得到不同物品的概率为 i n × n − i n \frac i n \times \frac {n-i} n ni×nn−i(忽略第一次就买到的情况),下 k k k 次得到不同物品的概率为 ( i n ) k − 1 × n − i n (\frac i n)^{k-1} \times \frac {n-i}n (ni)k−1×nn−i
这里假设第 k k k 次就是无穷次,则此步的期望为: E = 1 × n − i n + 2 × i n × n − i n + 3 × ( i n ) 2 × n − i n + . . . + k × ( i n ) k − 1 × n − i n E= 1 \times \frac {n-i} n + 2 \times \frac i n \times \frac {n-i} n+3 \times (\frac i n)^2 \times \frac {n-i} n+...+k \times (\frac i n)^{k-1} \times \frac {n-i} n E=1×nn−i+2×ni×nn−i+3×(ni)2×nn−i+...+k×(ni)k−1×nn−i
i n × E = 1 × i n × n − i n + 2 × ( i n ) 2 × n − i n + 3 × ( i n ) 3 × n − i n + . . . + k × ( i n ) k × n − i n \frac i n \times E= 1 \times \frac i n \times \frac {n-i} n + 2 \times (\frac i n)^2 \times \frac {n-i} n+3 \times (\frac i n)^3 \times \frac {n-i} n+...+k \times (\frac i n)^k \times \frac {n-i} n ni×E=1×ni×nn−i+2×(ni)2×nn−i+3×(ni)3×nn−i+...+k×(ni)k×