Luogu P2473 [SCOI2008]奖励关

比较恶心的几率(指望)+状压DP,想正推2H的我瑟瑟发抖git

因为数据范围不大,所以咱们能够直接状压每一个宝物取或不取的状况,设\(f_{i,j}\)表示前\(i\)轮且宝物是否取过的状态为\(j\)时的方案总数,可是咱们发现这样可能会致使一些不合法的状态也获得转移,所以咱们考虑倒推spa

\(f_{i,j}\)表示表示在第\(1\)轮到第\(i-1\)轮内宝物是否取过的状态为\(j\),第\(i\)轮到第\(k\)轮的最大指望得分,那么这样就能够经过倒推动行转移了。code

具体转移的时候咱们枚举全部的宝物限制,那么转移就很明显了it

不过因为这里要求的是指望值,而每一次须要除以\(n\),最后的\(f_{1,0}\)即为答案io

CODEclass

#include<cstdio>
#include<cctype>
using namespace std;
typedef double DB;
const int N=16,INF=-1e9;
int n,p[N],m,s[N],x,tot;
DB f[105][(1<<N)+5];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{   
    x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag;
}
inline int calc(int x)
{
    int res=0; while (x) res+=x&1,x>>=1; return res;
}
inline DB max(DB a,DB b)
{
    return a>b?a:b;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j,k; read(m); read(n); tot=(1<<n)-1;
    for (i=0;i<n;++i)
    {
        read(p[i]); read(x);
        while (x) s[i]|=(1<<x-1),read(x);
    }
    for (i=m;i>=1;--i)
    for (j=0;j<=tot;++j)
    {
        for (k=0;k<n;++k)
        if ((s[k]&j)==s[k]) f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k)]+p[k]); else f[i][j]+=f[i+1][j];
        f[i][j]=(DB)f[i][j]/n;
    }
    return printf("%.6lf",f[1][0]),0;
}
相关文章
相关标签/搜索