Loading

第23次CSP第四题 CSP202109-4 收集卡牌 100分(状压DP)

upd:
破案了,最后格式控制输出%.10lf才能过,%.8lf会WA,估计是ccf赛时测评和赛后的测评机不太一样..?

状压DP。下面的代码交上去0分,比赛写的暴力交上去也是0分,怀疑题库数据炸了2333不过下面的和暴搜拍过小数据是没问题的。等过一阵再试试。

#include <iostream>
using namespace std;
int n, k;
double p[200005];
double dp[400005][205];//dp[i][j]为i状态下手中有j个硬币的概率
double ans = 0;
int get(int x) {
    int ret = 0;
    while(x) {
        ret += (x & 1);
        x >>= 1;
    }
    return ret;
}
int main() {
    cin >> n >> k;
    
    for(int i = 0; i <= 200005; i++) {
        for(int j = 0; j <= 10; j++) {
            dp[i][j] = 0;
        }
    }
    for(int i = 0; i <= 100; i++) {
        dp[0][i] = 1;
    }
    for(int i = 1; i <= n; i++) {
        cin >> p[i];
    }
    for(int i = 1; i < (1 << n); i++) {
        for(int j = 0; j <= k * n; j++) {
            //直接抽卡获得
            for(int k = 0; k < n; k++) {
                if(((i >> k) & 1) && !(get(i ^ (1 << k)) == 0 && j)) {//不可能从dp[0][x]转移过来
                    int pre = i ^ (1 << k);
                    if(dp[pre][j] >= 0) dp[i][j] += dp[pre][j] * p[k + 1];
                }
            }
            //没抽到
            for(int k = 0; k < n; k++) {
                if(j != 0 && ((i >> k) & 1)) {
                    if(dp[i][j - 1] >= 0) {
                        dp[i][j] += dp[i][j - 1] * p[k + 1];
                        
                    }
                }
            }
            int num = get(i);
            if(num == n || num + (j / k) >= n) {//满足条件才能更新答案
                ans = ans + dp[i][j] * (num + j);
                dp[i][j] = -1;//到此为止 不会继续抽了
            }
        }
    }
    printf("%.10lf", ans);//%.10lf没问题 %.8lf会0分
    return 0;
}
// 10 7
// 0.1 0.1 0.2 0.05 0.05 0.02 0.08 0.2 0.1 0.1
// 10 5
// 0.03 0.07 0.26 0.04 0.1 0.16 0.17 0.07 0.04 0.06
posted @ 2021-09-29 23:57  脂环  阅读(997)  评论(0编辑  收藏  举报