我定义的状态数组存的是概率,而且是正推
达哥存的是期望,还逆推,然后我就懵比了
$f_{i,j,k}$ 第i关 j条命 连胜k次
$$f_{i+1,min(j+1,Q),min(k+1,R)}+=f_{i,j,k}*p$$
$$f_{i+1,j-1,0}+=f{i,j,k}*(1.0-p)$$
$$ans=sum_{i=1}^nsum_{j=0}^Qsum_{k=1}^R f_{i,j,k}*j$$
然后暴力dp会了,考虑矩阵乘优化
首先两维压成一维
剪枝:
1.命数!=Q&&命数<连胜数 就不用压
然后还可以再加一个位置,用来存期望
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cmath> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define rint register int #define dd double #define esp 0.0000001 using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } int n,R,Q,S; dd f[2][7][10006]; dd dp(dd p) { rint i,j,k; int nx,t1,t2,now=0; dd ans=0; for(j=0;j<7;++j) for(k=0;k<10006;++k) f[1][j][k]=0; f[1][Q][0]=1; for(i=0;i<n;++i) { now^=1; nx=now^1; for(j=0;j<=Q;++j) for(k=0;k<=R;++k) f[nx][j][k]=0; for(j=1;j<=Q;++j) for(k=0;k<=R;++k) { t1=j+1; if(t1>Q) t1=Q; t2=k+1; if(t2>R) t2=R; f[nx][t1][t2]+=f[now][j][k]*p; f[nx][j-1][0]+=f[now][j][k]*(1.0-p); } for(j=0;j<=Q;++j) for(k=0;k<=R;++k) ans=ans+f[nx][j][k]*k; } return ans; } dd work() { dd l=0,r=1,mid; while(l<r-esp) { mid=(l+r)/2.0; if(dp(mid)>=S) r=mid; else l=mid; } return l; } int main(){ //freopen("in.in","r",stdin); read(n); read(R); read(Q); read(S); //printf("%lf",dp(1)); printf("%lf",work()); }
#pragma GCC optimize("O3") #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cmath> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define rint register int #define dd double #define esp 0.00000001 using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } inline void readll(ll &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } int all,dui[10][31]; struct QTQ { dd b[155][155]; void clear() { mem(b,0); } void out() { printf(" "); for(int i=1;i<=all;++i) { for(int j=1;j<=all;++j) printf("%lf ",b[i][j]); printf(" "); } printf(" "); } QTQ operator * (const QTQ &c) const { QTQ x=*this,t; rint i,j,k; for(i=1;i<=all;++i) for(j=1;j<=all;++j) { t.b[i][j]=0; for(k=1;k<=all;++k) t.b[i][j]+=x.b[i][k]*c.b[k][j]; } return t; } }f,a,a1,a2; int n,R,Q; ll S; dd dp(dd p) { rint i,j; f.clear(); a1.clear(); a2.clear(); for(i=1;i<=Q;++i) for(j=0;j<=R;++j) if(i>=j||i==Q) { a1.b[dui[i][j]][dui[min(i+1,Q)][min(j+1,R)]]=p; a1.b[dui[i][j]][dui[i-1][0]]=(1.0-p); } a1.b[all][all]=1; for(i=0;i<=Q;++i) for(j=0;j<=R;++j) if(i>=j||i==Q) a2.b[dui[i][j]][all]=j; for(i=1;i<=all;++i) a2.b[i][i]=1; a=a1*a2; f.b[1][dui[Q][0]]=1; int ci=n; while(ci) { if(ci&1) f=f*a; a=a*a; ci>>=1; } return f.b[1][all]; } dd work() { dd l=0,r=1,mid; while(l<r-esp) { mid=(l+r)/2.0; if(dp(mid)>=S) r=mid; else l=mid; } return l; } int main(){ //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); //freopen("nt2012_contra.in","r",stdin); //freopen("nt2012_contra.out","w",stdout); rint i,j; read(n); read(R); read(Q); readll(S); all=0; for(i=0;i<=Q;++i) for(j=0;j<=R;++j) if(i>=j||i==Q) dui[i][j]=++all; ++all; if(dp(1.0)<=S)// ... 必须是<=,不然第一个点... { printf("Impossible. "); return 0; } printf("%lf",work()); }