//yxc注释版(位运算)
include [HTML_REMOVED]
include [HTML_REMOVED]
include [HTML_REMOVED]
using namespace std;
const int N = 16, M = 1 << N;//左移动一位,相当于乘2
int n, m;
double p[N];
double f[M][N * 5 + 1];
double dp(int state, int coins, int r)//动态规划算法,用于计算某个状态下的值。state:当前状态的表示,通常是一个位掩码,指示哪些元素已经被选择。
{
auto& v = f[state][coins];//存储已计算的值 v,f 是一个二维数组(或向量),用于缓存结果以避免重复计算。
if (v >= 0) return v;//如果 v 已经计算过(即 v 的值不小于 0),直接返回该值。这是动态规划的典型做法,利用记忆化来提高效率。
if (coins >= r * m) return v = 0;//终止条件
v = 0;//初始化,以便在后续计算中累加。
for (int i = 0; i < n; i ++ )
if (state >> i & 1)//检查当前元素 i 是否已经在 state 中被选择。通过右移操作和按位与运算来判断
v += p[i] * (dp(state, coins + 1, r) + 1);//如果元素 i 已被选择,则递归调用 dp,保持 state 不变,增加 coins 的数量,并加上 1(可能是计数当前选择的元素)。将结果乘以 p[i](可能是该元素的权重或概率),累加到 v。
else
v += p[i] * (dp(state | (1 << i), coins, r - 1) + 1);
return v;
}
int main()
{
scanf(“%d%d”, &n, &m);
for (int i = 0; i < n; i ++ ) scanf(“%lf”, &p[i]);
memset(f, -1, sizeof f);
printf("%.10lf\n", dp(0, 0, n));
return 0;
}