Codechef LEBOXES

    xiaoxiao2026-09-28  14

    原题链接

    CC LEBOXES

    题目大意

    一共有 n 个袋子和m个粮食。 每个粮食需要支付 Ci 的金钱和 Di 的钻石购买。 每个袋子有 Pi 的概率装有 Vi 的金币,有 1−pi 的概率装有1个钻石。 问每个袋子都打开的情况下,期望拿到多少个粮食。

    n,m≤30;Vi,Ci≤107

    解题思路

    meet in the middle

    将盒子分为前后两个部分.对于每部分,我们暴力枚举状态 (V,D,P) 表示获得 V 的金钱,D个钻石,概率为 P ,将状态按D的值分类。

    对于每个部分,将 D 值相同的按金钱数排序,并维护前缀概率和。

    dp,fi,j表示在拥有 i 个钻石的情况下,获得j个粮食的最小花费金钱数,这个其实就是一个简单的背包问题。

    最后,我们需要,将前后两个部分合并,枚举 i,j,k ,表示前半部分获得 i 个钻石,后半部分获得j个钻石,最终获得 k 个粮食,求当前概率。

    易得需要钱数≥fi+j,k,然后我们就是在排序后的状态使用两个指针扫描即可。

    参考代码

    #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define maxn 35 #define maxp 50005 #define db double #define ld long double #define pild pair<int,ld> #define fi first #define se second #define mp(a,b) make_pair(a,b) #define mem(a,b) memset(a,b,sizeof(a)) #define min(a,b) (((a) < (b)) ? a : b) using namespace std; int T,n,m,mid; int f[maxn][maxn],c[maxn],d[maxn]; db p[maxn],ans; int v[maxn]; int tot[2][maxn]; pild st[2][maxn][maxp]; void dfs(int w,int to,int money,int dio,ld pp){ if (w==to) { if (w==mid+1) { tot[0][dio]++; int tmp=tot[0][dio]; st[0][dio][tmp]=mp(money,pp); } else { tot[1][dio]++; int tmp=tot[1][dio]; st[1][dio][tmp]=mp(money,pp); } return; } dfs(w+1,to,money,dio+1,pp*(1-p[w])); dfs(w+1,to,money+v[w],dio,pp*p[w]); } int main(){ scanf("%d",&T); while (T--) { mem(tot,0); mem(f,63); mem(c,0); mem(d,0); ans=0; scanf("%d%d",&n,&m); fo(i,1,n) { scanf("%d%lf",&v[i],&p[i]); p[i] /= 100; } fo(i,1,m) scanf("%d%d",&c[i],&d[i]); f[0][0]=0; fo(i,1,m) fd(j,i,1) fo(k,0,n-d[i]) f[j][k+d[i]]=min(f[j][k+d[i]],f[j-1][k]+c[i]); fo(i,1,m) fo(j,1,n) f[i][j]=min(f[i][j],f[i][j-1]); mid=n / 2; dfs(1,mid+1,0,0,1); dfs(mid+1,n+1,0,0,1); fo(i,1,mid) { sort(st[0][i]+1,st[0][i]+tot[0][i]+1); st[0][i][tot[0][i]+1].se=0; fd(j,tot[0][i],0) st[0][i][j].se+=st[0][i][j+1].se; } fo(i,1,n-mid) { sort(st[1][i]+1,st[1][i]+tot[1][i]+1); st[1][i][tot[1][i]+1].se=0; fd(j,tot[1][i],0) st[1][i][j].se+=st[1][i][j+1].se; } fo(i,0,mid) { if (tot[0][i]==0) continue; fo(j,0,n-mid) { if (tot[1][j]==0) continue; fo(k,1,m) { if (f[k][i+j]>1e9) continue; int money=f[k][i+j]; int w=tot[0][i]; fo(l,1,tot[1][j]) { while (w && st[0][i][w].fi+st[1][j][l].fi>=money) w--; ans+=(st[1][j][l].se-st[1][j][l+1].se)*st[0][i][w+1].se; } } } } printf("%.4lf\n",ans); } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-1312422.html
    最新回复(0)