Scx117
只一眼,便辽阔了时间。

题意:你的英雄一开始血量为p,你还有m个队友,血量无穷。血量上限为n,下限为0。如果血量满了就不能加血。每次启动操作,随机给m+1个英雄加1点血,然后等概率随机k次每次对于英雄扣1点血。求期望操作几次你的英雄没血?

n,m,p<=1500.

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mod=1e9+7; 
 5 const int N=1505;
 6 int n,p,m,k,f[N],inv[N],g[N][N],ans[N];
 7 int ksm(int x,int y)
 8 {
 9     int res=1;
10     while (y) {if (y&1) res=(ll)res*x%mod; y>>=1;x=(ll)x*x%mod;}
11     return res;
12 }
13 int Inv(int x){return ksm(x,mod-2);}
14 void gauss()
15 {
16     for (int i=n;i>=2;i--)
17     {
18         if (g[i][i]==0&&g[i-1][i]==0) {puts("-1");return;}
19         if (g[i][i]==0) 
20         {
21           for (int j=1;j<=i;j++) swap(g[i][j],g[i-1][j]);
22           swap(g[i][n+1],g[i-1][n+1]);
23         }
24         else
25         {
26           if (!g[i-1][i]) continue;
27           int v=(ll)g[i-1][i]*Inv(g[i][i])%mod;
28           for (int j=1;j<=i;j++)
29             g[i-1][j]=((ll)g[i-1][j]-(ll)g[i][j]*v%mod+mod)%mod;
30           g[i-1][n+1]=((ll)g[i-1][n+1]-(ll)g[i][n+1]*v%mod+mod)%mod;
31         }
32     }
33     for (int i=1;i<=p;i++)
34     {
35         ans[i]=g[i][n+1];
36         for (int j=1;j<i;j++)
37           ans[i]=((ll)ans[i]-(ll)ans[j]*g[i][j]%mod+mod)%mod;
38         ans[i]=(ll)ans[i]*Inv(g[i][i])%mod;
39         if (!ans[i]) {puts("-1");return;}
40     }
41     printf("%d\n",ans[p]);
42 }
43 void init()
44 {
45     memset(g,0,sizeof(g));
46     int tmp=1,c=1,in,inn;in=inn=Inv(m+1);
47     for (int i=1;i<=min(n,k);i++)
48     {
49         c=(ll)c*(k-i+1)%mod*inv[i]%mod;
50         tmp=(ll)tmp*in%mod;
51         f[i]=(ll)c*tmp%mod;
52     }
53     in=(ll)m*in%mod;tmp=ksm(in,k-min(n,k));
54     f[0]=1;
55     for (int i=min(n,k);i>=0;i--)
56       f[i]=(ll)f[i]*tmp%mod,tmp=(ll)tmp*in%mod;
57     
58     for (int i=1;i<=n;i++)
59     {
60         if (i==n) in=1,inn=0;
61         for (int j=max(i-k,0);j<=i;j++) 
62         {
63           g[i][j]=((ll)g[i][j]+(ll)f[i-j]*in%mod)%mod;
64           if (j+1<=n) g[i][j+1]=(ll)f[i-j]*inn%mod;
65         }
66         g[i][i]=((ll)g[i][i]-1+mod)%mod;g[i][n+1]=mod-1;
67     }
68 }
69 int main()
70 {
71     int T;scanf("%d",&T);
72     inv[0]=inv[1]=1; for (int i=2;i<=1500;i++) inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
73     while (T--) {
74         scanf("%d%d%d%d",&n,&p,&m,&k);
75         init();gauss();
76     }
77     return 0;
78 }

 

易错点:1.注意对无解的特判,如果有概率为0就是-1。

 

题解:dp+高斯消元

一般dp式子:dp[i]表示还剩下i滴血直到英雄死去的期望操作次数。分自己的英雄是否加血讨论。f[i]表示血量减少i的概率,可以预处理。

$dp[i]=(\sum_{j=i-k}^{i}dp[j]*f[i-j]*m/(m+1)+\sum_{j=i-k+1}^{i+1}dp[j]*f[i+1-j]*1/(m+1))+1$。

但是由于有dp[i+1],难以递推。考虑设未知数进行高斯消元。高斯消元不是n^3*logn的吗?

由于这个矩阵写出来是阶梯状往右,第i行的最右边元素只到i+1,所以只用下面一行来减去它,化成右下三角矩阵求即可。时间复杂度O(n^2(*logn))。

或者直接用前n-1个式子写出dp[i]=Ax+B的表达式,然后再全部代入最后一个dp[n]=....的式子中,解Ax+B=A'x+B'即可。

posted on 2018-04-24 08:13  Scx117  阅读(111)  评论(0编辑  收藏  举报