bzoj_2676_Contra

我定义的状态数组存的是概率,而且是正推

达哥存的是期望,还逆推,然后我就懵比了

$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}^n\sum_{j=0}^Q\sum_{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());
}
bao_li

 

#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("\n");
        for(int i=1;i<=all;++i)
        {
            for(int j=1;j<=all;++j)
                printf("%lf ",b[i][j]);
            printf("\n");
        }
        printf("\n");
    }
    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.\n");
        return 0;
    }
    printf("%lf",work());
}
ju_zhen_you_hua

 

posted @ 2017-10-24 21:19  A_LEAF  阅读(168)  评论(0编辑  收藏  举报