ybtoj Au 期望概率 DP
前言中的前言
-
由于本人过菜,有些题解会咕掉,请原谅这个蒟蒻
-
由于本人过菜,不知道什么时候就
了,想给这个机房留下点什么…… -
如果想看高效进阶的题解,建议出门左拐,去云落那里看看,保证是全网最全最好的,但不要对云落的博客好奇,更不要看云落的一言 和 云落的合集:黑夜刀己,白日爱人
-
后记会有一些逻辑不通,无病呻吟,像幼儿园写的话的句子,请见谅(建议跳过)
正片开始!
题面
前言
期望 T1,水题
正文
设长度为
注意上面两个都不是期望
若第
不成功,
根据全期望公式(对于全期望公式,我的理解是分类讨论)
显然
这里也是全期望公式
至此,所有变量都可求
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
double p[N],a[N],b[N],f[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i];
a[i]=(a[i-1]+1)*p[i];
b[i]=(b[i-1]+2*a[i-1]+1)*p[i];
f[i]=f[i-1]+(3*b[i-1]+3*a[i-1]+1)*p[i];
}
printf("%.1lf",f[n]);
return 0;
}
后记
心空,心虚
题面
前言
期望 T2,想咕题
但我的良知告诉我不能咕
好吧,其实也没那么想咕
这题当时看着挺难的还问了才队……
正文
其实就是维护一个期望逆序对数
考虑一个人,他可以选
第一本书,第一轮被选的概率为
第二轮为
第三轮为
……
所以第一本书被选的概率为
发现这玩意是个等比数列
求和公式:
显然此时公比<0
好的,那么第一本书被选的概率就是
可以发现第二本书就是在这基础上
最后用树状树组维护一下逆序对即可
代码
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m;
struct node{int a,b;}d[N];
long double p,ans,e[N],cnt[N];
bool cmp(node x,node y){
if(x.a==y.a)return x.b<y.b;
return x.a<y.a;
}
int lowbit(int x){return x&-x;}
void add(int x,long double dd){
for(;x<=n;x+=lowbit(x))e[x]+=dd;
}
long double query(int x){
long double res=0;
for(;x;x-=lowbit(x))res+=e[x];
return res;
}
int main(){
cin>>n>>m>>p;
for(int i=1;i<=n;i++)cnt[i]=1;
for(int i=1;i<=m;i++){cin>>d[i].a>>d[i].b;cnt[d[i].a]*=(1-p);}
d[0].a=0,d[0].b=0;
sort(d+1,d+1+m,cmp);
long double S=1;
for(int i=1;i<=m;i++){
if(d[i].a!=d[i-1].a)S=1;
long double w=S*p/(1-cnt[d[i].a]);
ans+=(query(n)-query(d[i].b))*w;
add(d[i].b,w);
S*=1-p;
}
printf("%.2llf",ans);
return 0;
}
后记
不敢回忆
题面
前言
期望 T3,水题
正文
设
就完了
写代码时注意一下边界即可
代码
#include <bits/stdc++.h>
using namespace std;
int n,t;
long double p;
long double f[2005][2005];
int main(){
cin>>n>>p>>t;
f[0][0]=1;
for(int i=1;i<=t;i++){
for(int j=0;j<=n;j++){
if(j==n)f[i][j]=f[i-1][j-1]*p+f[i-1][j];
else if(j==0)f[i][j]=f[i-1][j]*(1-p);
else{ f[i][j]+=f[i-1][j-1]*p;
f[i][j]+=f[i-1][j]*(1-p);}
}
}
long double ans=0;
for(int i=1;i<=n;i++){
ans+=f[t][i]*i;
}
cout<<ans;
return 0;
}
后记
好不容易自己做出来一道,你告诉我这是黄题???
题面
前言
期望 T4,综合题
会小讲一下高斯消元
正文
看起来是道构造题,但很容易想到让他经过的期望次数多的边编号尽量小
现在就是要求每条边经过的期望次数
设
容易推出
所以现在要求每个点经过的期望次数
容易推出
特殊的当
当
所以让
发现这个式子用高斯消元能做
代码
#include <bits/stdc++.h>
using namespace std;
const int N=125005;
int n,m,cnt,head[N],in[N];
long double a[505][505],kazuha,g[N];
struct node{int to,nxt;}e[N];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int uu[N],vv[N];
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>uu[i]>>vv[i];
add(uu[i],vv[i]),add(vv[i],uu[i]);
in[uu[i]]++,in[vv[i]]++;
}
n--;
for(int i=1;i<=n;i++){
if(i==1)a[i][n+1]=-1;
a[i][i]=-1;
for(int j=head[i];j;j=e[j].nxt){
int v=e[j].to;
if(v!=n+1)a[i][v]=1.0/in[v];
}
}
for(int i=1;i<=n;i++){
int maxn=i;
for(int j=i+1;j<=n;j++){
if(fabs(a[j][i])>fabs(a[maxn][i]))maxn=j;
}
for(int j=n+1;j>=1;j--){
swap(a[maxn][j],a[i][j]);
}
for(int j=n+1;j>=1;j--){
a[i][j]/=a[i][i];
}
for(int j=1;j<=n;j++){
if(j!=i){
double temp=a[j][i];
for(int k=1;k<=n+1;k++){
a[j][k]-=temp*a[i][k];
}
}
}
}
for(int i=1;i<=m;i++){
g[i]=a[uu[i]][n+1]/in[uu[i]]+a[vv[i]][n+1]/in[vv[i]];
}
sort(g+1,g+m+1);
for(int i=1;i<=m;i++){
kazuha+=g[i]*(m-i+1);
}
printf("%.3llf\n",kazuha);
return 0;
}
后记
有的爱像阳光倾落,边拥有边失去着
题面
前言
期望 T5,应用题
正文
这道题的精髓就在于答案统计
提示:因为他是个环,所以要有一个很别扭的状态设计
设
设
转移:
这个很好理解
然后就是怎么统计答案了
来再看看状态吧
第一个和第二个的颜色不同
为了避免容斥的状态
所以这里第一个球他就不是一个球,而是一个连续段,压缩成的一个球
设这个连续段的长度为
第一个球选这个连续段里的哪个都行,所以有
所以答案统计就为
没有
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=205;
int n,m;
long double f[N][2],g[N];
signed main(){
cin>>n>>m;
g[1]=1.0;
for(int i=2;i<=n;i++)g[i]=g[i-1]/m;
f[1][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
f[i][0]+=j*g[j]*(f[i-j][0]*(m-2)/m+f[i-j][1]*(m-1)/m);
f[i][1]+=j*g[j]*f[i-j][0]/m;
}
}
long double kazuha=g[n]*n;
for(int i=1;i<n;i++)kazuha+=i*i*f[n-i+1][0]*g[i];
printf("%.5llf",kazuha);
return 0;
}
后记
好想看微信……
不敢看微信……
题面
前言
期望 T6,应用题
正文
每个按键都不可能被其他按键的组合键替代,按了其他的键就还要必须按一个相同的键给按回来,这样我们就可以dp了
设
这个状态就很神,他没有设最终的状态,他设的是一个过程量
转移也很好理解
就是有
按错了就多了一个未归位按键,需要一步把他按回来,按回来后还是有
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e5+3;
int n,k,a[mod],f[mod],cnt;
int qpow(int a,int b){
int ans=1;
while(b){
if(b%2)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=n;i>=1;i--){
if(a[i]){
cnt++;
for(int j=1;j*j<=i;j++){
if(i%j==0){
a[j]^=1;
if(j*j!=i)a[i/j]^=1;
}
}
}
}
for(int i=n;i>=1;i--){
f[i]=(n+(n-i)*f[i+1]%mod)%mod*qpow(i,mod-2)%mod;
}
int kazuha=k;
if(cnt<=k)kazuha=cnt;
else{
for(int i=cnt;i>k;i--){
kazuha=(kazuha+f[i])%mod;
}
}
for(int i=1;i<=n;i++)kazuha=kazuha*i%mod;
cout<<kazuha;
return 0;
}
后记
这年头做个题都被刀
(注意到原题一句话:Zeit und Raum trennen dich und mich)
禁止使用翻译
题面
前言
期望 T7,大水题(本蒟蒻都能切)
正文
直观的
设
当
当
最后统计答案时就统计
时间复杂度
发现给
因为
最后统计答案就统计
还有一个问题是背包容量的上限
发现只要
于是
时间复杂度
下表为负需要平移一下
代码
#include <bits/stdc++.h>
using namespace std;
const int N=205;
int n,l,K,a[N];
long double p[N],f[2][N<<1][N];
int main(){
cin>>n>>l>>K;
for(int i=1;i<=n;i++){
cin>>p[i];
p[i]/=100.0;
// cout<<p[i]<<" ";
}
for(int i=1;i<=n;i++)cin>>a[i];
K=min(n,K);
f[0][n+K][0]=1;
int d=0;
for(int i=1;i<=n;i++){
d^=1;
// cout<<d<<endl;
for(int k=0;k<=n;k++){
for(int j=0;j<=n*2;j++){
f[d][j][k]=(1-p[i])*f[d^1][j][k];
}
}
for(int k=0;k<n;k++){
for(int j=1;j<=n*2;j++){
f[d][min(j+a[i],n*2)][k+1]+=p[i]*f[d^1][j][k];
}
}
}
long double kazuha=0;
for(int i=n;i<=2*n;i++){
for(int j=l;j<=n;j++){
kazuha+=f[n&1][i][j];
}
}
printf("%.6llf",kazuha);
return 0;
}
后记
或许,我爱上的不是她,而是我的想象力
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】