P2473题解

P2473奖励关

题目大意

自己看

题目分析

首先注意到 \(1 \leq n \leq 15\),很容易可以想到状压。定义一个数组 \(f_{i,j}\) 表示第 \(i\) 轮时状态为 \(j\) 的期望。那么容易想到转移就是直接把上一步的所有可行状态相加再除以状态数,但我们会发现,无法判断此时的选择能否战未来,有后效性无法判断,所以考虑逆推:

\[f_{i,j}=\frac{1}{n} \sum_{k=1}^n \begin{cases} \max(f_{i+1,j},f_{i+1,j|(1<<k-1)}+p_k)(j \& s_k = s_k) \\ f_{i+1,j}(j \& s_k \ne s_k) \end{cases} \]

即可

代码

#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N=100+5;
int n,K;
int p[N],s[N];
double f[N][(1<<18)+5];
int main()
{
    cin>>K>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>p[i];
        int t=1;
        while(t)
        {
            cin>>t;
            if(!t)break;
            s[i]|=(1<<(t-1));
        }
    }
    for(int i=K;i>=1;i--)
    {
        for(int j=0;j<(1<<18);j++)
        {
            for(int k=1;k<=n;k++)
            {
                if((j&s[k])==s[k])f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(k-1))]+p[k]);
                else f[i][j]+=f[i+1][j];
            }
            f[i][j]/=n;
        }
    }
    printf("%.6lf",f[1][0]);
}
posted @ 2026-07-16 15:25  tidewave  阅读(17)  评论(0)    收藏  举报