luogu P3239 [HNOI2015]亚瑟王
题面传送门
因为每次有一轮打出一发就不打了的限制所以不能直接期望去算。
考虑一个点\(i\)之前如果打出了\(j\)个技能,无论这\(j\)个技能是啥,\(i\)这个点都会被打\(r-j\)次,这启发我们设\(f_{i,j}\)为\(1\)到\(i\)点打出\(j\)次的概率。
有了这个就可以算每个点被打出的期望了,根据期望的线性性直接乘伤害加起来就好了。
时间复杂度\(O(Tnr)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (220+5)
#define M (40+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,T,A[N+5],Ne,La;db Ans,P[N+5],dp[2][N],Po[N+5];
I void Solve(){
RI i,j;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%lf%d",&P[i],&A[i]);
Ans=0;Me(dp,0);dp[0][0]=1;for(i=1;i<=n;i++){
Ne=i&1;La=Ne^1;Me(dp[Ne],0);for(Po[0]=j=1;j<=m;j++) Po[j]=Po[j-1]*(1-P[i]);
for(j=0;j<=m;j++) dp[Ne][j]+=dp[La][j]*Po[m-j],dp[Ne][j+1]+=dp[La][j]*(1-Po[m-j]),Ans+=A[i]*dp[La][j]*(1-Po[m-j]);
}printf("%.10lf\n",Ans);
}
int main(){
freopen("1.in","r",stdin);
scanf("%d",&T);while(T--) Solve();
}