题目翻译
数轴上有 $n$ 个点,每次可以选择点 $x$ ,从 $x-1$ 或 $x+1$ 中等概率选择一个点,作关于此点的对称点,共 $k$ 轮,问每个点所在位置的期望。
$solution:$
若此刻选择 $i$ 点移动,设 $f_i$ 表示 $i$ 点的期望,则 $f_i=f_{i-1}+f_{i+1}-f_i$ ,暴力 $dp$ ,时间复杂度 $O(nk)$ ,无法通过此题。
考虑差分,设 $d_i=f_i-f_{i-1}$ ,若 $i$ 点移动后, $d_i=f_i-f_{i-1}=f_{i-1}+f_{i+1}-f_i-f_{i-1}=f_{i+1}-f_{i}\d_{i+1}=f_{i+1}-f_i=f_{i+1}-(f_{i-1}+f_{i+1}-f_i)=f_i-f_{i+1}$ 。
所以当 $i$ 点移动的本质是交换 $d_i,d_{i+1}$ ,设 $g_{i,j}$ 表示 $i$ 号经过 $2^j$ 次后的差分数组,直接倍增维护即可。
时间复杂度 $O(log k)$
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=100001; int m,k,ans,n,x[MAXN],d[MAXN],a[MAXN],fa[MAXN][61],p[MAXN]; signed main(){ // freopen("2.in","r",stdin); n=read(); for(int i=1;i<=n;i++) x[i]=read(),d[i]=i,p[i]=x[i]-x[i-1]; m=read(),k=read(); for(int i=1;i<=m;i++) a[i]=read(),swap(d[a[i]],d[a[i]+1]); for(int i=1;i<=n;i++) fa[i][0]=d[i]; for(int j=1;j<=60;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; for(int i=1;i<=n;i++){ int res=i; int K=k; for(int j=60;j>=0;j--) if(K-(1ll<<j)>=0) K-=(1ll<<j),res=fa[res][j]; ans+=p[res]; printf("%.1f ",(double)ans); }return 0; }/* 3 1 -1 1 2 2 2 2 */