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