[关闭]
@ysner 2018-08-17T21:42:18.000000Z 字数 2747 阅读 2283

[国家队集训]最短路

期望 DP 数论 自治领


题面

考虑一张个点的无向完全图,总共有条边。每条边有的概率存在,的概率不存在。
现在等概率在个点中随机选一个,求号点到它的最短距离(经过的边数)。
如果号点和它不连通,则认为答案是 。求期望答案。

解析

不难发现,在当前题目条件下,除了节点,其它点期望是一样的。

可以考虑从号点出发,由近到远地统计各个点的期望。(然而我考场上是反过来想的,于是逃不过后效性这个大坑)
据说这个概念叫树???(深度等于距离)

算法

一个想法是设表示当前统计到到第层(离号点距离为)、已经统计了个点的答案、用其中的个点与下一层的(枚举)个点相连(往下拓展)的任意一点的期望。
(至于为什么这么多维,尝试列下转移式就知道了)

那么,枚举一下,转移是这样的

  1. if(i+1==n-1)
  2. add(f[i+1][sum+t][t],1ll*f[i][sum][s]*lk[s][t]%mod*C[n-sum][t]%mod);
  3. else
  4. add(f[i+1][sum+t][t],1ll*f[i][sum][s]*lk[s][t]%mod*dlk[s][n-sum-t]%mod*C[n-sum][t]%mod);

表示个点起码被中一个点连了的概率,即
表示个点与个点完全没边的概率,即

统计答案,就是把当前层所有点的距离(就是层编号)乘上概率,得到当前层的期望,加入答案。
注意不连通这一情况还要单独乘概率

  1. for(int d = 0; d <= n-1; d ++)
  2. for(int sum = 1; sum <= n; sum ++)
  3. for(int s = 1; s <= sum; s ++)
  4. if(f[d][sum][s])
  5. {
  6. add(Ans,1ll*f[d][sum][s]*s%mod*d%mod) ;
  7. add(Ans,1ll*f[d][sum][s]*(n-sum)%mod*dlk[s][n-sum]%mod*(1e9)%mod);
  8. }

复杂度

算法

发现由于每次向下只转移一层,那个没有什么卵用(但是它要统计进答案)。
考虑把它弄掉。

我们不枚举了,并把这一维从状态中删掉。

注意到(为概率,为期望)



则我们可以把数组分为两个,表示当前已经统计了个点的答案,表示将用其中个点与下一层点相连。则表示该状态下的概率和,表示该状态的期望和(即概率乘期望)。

于是每层任意一点对答案产生的贡献转变为

怎么转移
枚举,乘上该层连通的概率和方案数(选出中的个点),
就可以转移给,
就可以转移给

最后要乘上。(没错,算法统计了,这里没统计)
复杂度

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int mod=998244353,N=500,M=1e6;
  17. ll n,p,inv,ans,f[N][N],g[N][N],C[N][N],np,b[N],lk[N][N],dlk[N][N];
  18. bool vis[N];
  19. il ll gi()
  20. {
  21. re ll x=0,t=1;
  22. re char ch=getchar();
  23. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  24. if(ch=='-') t=-1,ch=getchar();
  25. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  26. return x*t;
  27. }
  28. il ll ksm(re ll S,re ll o)
  29. {
  30. re ll T=S;S=1;
  31. while(o)
  32. {
  33. if(o&1) S=S*T%mod;
  34. T=T*T%mod;
  35. o>>=1;
  36. }
  37. return S;
  38. }
  39. il void Pre()
  40. {
  41. b[0]=1;fp(i,1,n) b[i]=b[i-1]*np%mod;
  42. fp(i,0,n) fp(j,0,n) lk[i][j]=ksm(mod+1-b[i],j);
  43. fp(i,0,n) fp(j,0,n) dlk[i][j]=ksm(np,i*j);
  44. fp(i,0,n)
  45. {
  46. C[i][0]=1;
  47. fp(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
  48. }
  49. }
  50. il void DP()
  51. {
  52. f[1][1]=1;g[1][1]=0;
  53. fp(sum,1,n-1)
  54. fp(j,1,sum)
  55. if(f[sum][j])
  56. {
  57. (ans+=(mod+1-b[j])*(f[sum][j]+g[sum][j])%mod)%=mod;
  58. (ans+=dlk[n-sum][j]*f[sum][j]%mod*((ll)(1e9)%mod)%mod)%=mod;
  59. fp(k,1,n-sum-1)
  60. {
  61. re ll xs=lk[j][k]*dlk[j][n-sum-k]%mod*C[n-sum-1][k]%mod;
  62. (f[sum+k][k]+=xs*f[sum][j]%mod)%=mod;
  63. (g[sum+k][k]+=xs*((f[sum][j]+g[sum][j])%mod)%mod)%=mod;
  64. }
  65. }
  66. }
  67. int main()
  68. {
  69. n=gi();p=gi();inv=ksm(M,mod-2);
  70. np=(M-p)*inv%mod;
  71. Pre();DP();
  72. printf("%lld\n",ans*(n-1)%mod*ksm(10,6*n*n)%mod);
  73. return 0;
  74. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注