SS241007D. 航行(sail)
SS241007D. 航行(sail)
题意
在区间 \([1,n]\) 上,每个位置有参数 \(p_i\),每个时刻,你在 \(i\) 航道,有 \(p_i\) 的概率速度 \(-1\),有 \(1-p_i\) 的概率速度 \(+1\),然后你会来到 \(i+v\) 的位置。
如果你走到了 \(1\) 左边或者 \(n\) 右边,行驶结束。
问对于每个位置 \(i \in [1,n]\),\(0\) 时刻你在 \(i\) 位置,速度为 \(0\),问期望多久时间结束。无法结束输出 \(-1\)。
思路
显然的期望 DP。
设 \(f_{i,v}\) 表示在第 \(i\) 个航道,速度为 \(v\),期望结束用时。转移有 \(1-p_i\) 的概率到 \(f_{i+v+1,v+1}\),\(p_i\) 的概率到 \(f_{i+v-1,v-1}\)。
状态是 \(O(n^2)\),高斯消元,总时间复杂度是 \(O(n^6)\)。
可以搜索判一下是否存在无法结束的情况,或者高斯消元直接判无解(?)。
发现速度 \(v\) 只会取到 \(\sqrt{n}\)。因为如果 \(v > \sqrt{n}\),算个等差数列,\(\frac{(1+\sqrt{n})\sqrt{n}}{2}\),直接就出界了。所以 \(v\) 是 \(O(\sqrt{n})\) 级别的。直接取 \(2\sqrt{n}\)。时间复杂度变成 \(O(n^{4.5})\)。
发现我们只需要求所有的 \(f_{i,0}\),考虑 DP 预处理一下这些转移,尝试得到只和 \(f_{i,0}\) 有关的转移式子。
发现之前那个转移式子转移的时候 \(v\) 是连续的。也就是说 \(f_{i,0}\) 开始,第一次转移到一个 \(v=0\) 的地方过程中符号是相同的,所以对于 \(j>i\),转移途中所有 $v \neq 0 $ 的 \(k\) 是单调无环的,也就是说我们可以 \(O(n^{1.5})\) 求出 \(f_{i,0} \gets [j>i] f_{j,0}\) 的转移式子。同理可求 \(j<i\)。因此这里预处理复杂度是 \(O(n^{2.5})\)。
然后得到所有 \(f_{i,0}\) 的方程,高斯消元即可。时间复杂度 \(O(n^3)\)。
code
不会期望概率题,如何才能深刻理解期望?
对于一些细节的理解:
DP 的时候要记概率和期望,要理解概率是转移到状态 \((i,v)\) 的概率,理解期望,期望可以理解为 \(\frac{总代价}{方案数}\),这里没有具体的方案数,只有概率,因此期望就是 \(\sum 代价 \times 概率\)。其中假设无法到达 \(x\) 的方案,到达 \(x\) 的代价为 \(0\)。
概率的转移是简单的,状态 \(i\) 转移到状态 \(j\),有 \(f_j \gets f_j+f_i p_i\)。
期望的转移需要深刻理解。根据 \(\sum 代价 \times 概率\),得 \(E_j \gets E_j+(E_i+1 \times f_i)p_i\)。
仍然不是很能理解。
还需要记录 \(f_{i,0}\) 在到达下一个 \(v=0\) 的状态之前已经出界的情况。概率和期望相加。
如何构造高斯消元的矩阵?(下文的 \(p_j\) 表示上文的 \(f_j\)。)
根据有向图随机游走这种期望 DP 的模型,我们有 \(f_i \gets \sum_j p_j f_j + E_{i\to j}+(出界的代价 \times 概率=出界的期望)\)。
因为我们这里的 \(E\) 的概率算的就是 \(i\to j\) 的概率,因此 \(E\) 不需要乘上 \(p_j\)。
然后移个项就可以高斯消元了。
我太菜了,要参考蔡队的代码才能写。
英语白痴拼音命名法 yyds
#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
constexpr int N=505,mod=998244353,T=50;
int n;
int p[N];
int inv;
ll add(ll a,ll b) { return a+b>=mod?a+b-mod:a+b; }
void _add(ll &a ,ll b) { a=add(a,b); }
ll ksm(ll a,ll b=mod-2) {
ll s=1;
while(b) {
if(b&1) s=s*a%mod;
a=a*a%mod;
b>>=1;
}
return s;
}
int t;
ll gl[N][T],qw[N][T],togl[N][N],toqw[N][N];
typedef pair<int,int> pii;
#define fi first
#define se second
vector<pii > to[N][T];
bool vi[N];
#define inrange(x) (x>=1&&x<=n)
ll gs[N][N];
void dp0(int s) {
memset(gl,0,sizeof(gl)); memset(qw,0,sizeof(qw));
gl[s+1][1]=qw[s+1][1]=add(1,mod-p[s]);
rep(i,s+1,n) {
rep(v,1,t) {
_add(gl[min(i+v+1,n+1)][v+1],gl[i][v]*add(1,mod-p[i])%mod);
_add(qw[min(i+v+1,n+1)][v+1],add(gl[i][v],qw[i][v])*add(1,mod-p[i])%mod);
_add(gl[min(i+v-1,n+1)][v-1],gl[i][v]*p[i]%mod);
_add(qw[min(i+v-1,n+1)][v-1],add(gl[i][v],qw[i][v])*p[i]%mod);
}
}
rep(i,s,n) togl[s][i]=gl[i][0],toqw[s][i]=qw[i][0];
rep(v,0,t) _add(togl[s][0],gl[n+1][v]),_add(toqw[s][0],qw[n+1][v]);
}
void dp1(int s) {
memset(gl,0,sizeof(gl)); memset(qw,0,sizeof(qw));
gl[s-1][1]=qw[s-1][1]=p[s];
per(i,s-1,1) {
rep(v,1,t) {
_add(gl[max(0,i-v-1)][v+1],gl[i][v]*p[i]%mod);
_add(qw[max(0,i-v-1)][v+1],add(gl[i][v],qw[i][v])*p[i]%mod);
_add(gl[max(0,i-v+1)][v-1],gl[i][v]*add(1,mod-p[i])%mod);
_add(qw[max(0,i-v+1)][v-1],add(gl[i][v],qw[i][v])*add(1,mod-p[i])%mod);
}
}
per(i,s,1) togl[s][i]=gl[i][0],toqw[s][i]=qw[i][0];
rep(v,0,t) _add(togl[s][0],gl[0][v]),_add(toqw[s][0],qw[0][v]);
}
void dfs(int u) {
if(vi[u]) return;
vi[u]=1;
rep(i,1,n) if(togl[i][u]) dfs(i);
}
ll m[N][N];
ll ans[N];
void gaosi () {
rep(i,1,n) {
int r=i;
for(;r<=n&&!m[r][i];r++) ;
if(!m[r][i]) continue;
if(r!=i) swap(m[r],m[i]);
ll div=ksm(m[i][i]);
rep(j,i,n+1) m[i][j]=m[i][j]*div%mod;
rep(j,i+1,n) if(m[j][i]) {
div=m[j][i];
rep(k,i,n+1) _add(m[j][k],mod-m[i][k]*div%mod);
}
}
ans[n]=m[n][n+1];
per(i,n-1,1) {
ans[i]=m[i][n+1];
rep(j,i+1,n) _add(ans[i],mod-m[i][j]*ans[j]%mod);
}
}
int main() {
#ifdef LOCAL
freopen("my.out","w",stdout);
#else
freopen("sail.in","r",stdin);
freopen("sail.out","w",stdout);
#endif
inv=ksm(100);
sf("%d",&n);
t=ceil(sqrt(2*n));
rep(i,1,n) sf("%d",&p[i]), p[i]=1ll*p[i]*inv%mod;
rep(i,1,n) dp0(i),dp1(i);
dfs(0);
rep(i,1,n) {
if(!vi[i]) continue;
m[i][n+1]=toqw[i][0];
m[i][i]=1;
rep(j,1,n) if(i!=j&&vi[j]) _add(m[i][j],mod-togl[i][j]),_add(m[i][n+1],toqw[i][j]);
}
gaosi();
rep(i,1,n) {
if(!vi[i]) pf("-1 ");
else pf("%lld ",ans[i]);
}
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18513250