C. LRU
按最近最少使用原则,维护
n
首歌曲的缓存,缓存容量为
倒过来考虑,问题等价于不断按给定概率选取歌曲,直到选取了
用一个20位的二进制数来表示歌曲的集合,dp求每个集合可取得的概率,具体见代码。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
double dp[1<<20];
double p[22];
double ans[22];
int bit_cnt[1<<20];
int main(){
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>p[i];
}
int End = 1<<(n);
for(int i=1;i<End;i++){
//注意这个内置位运算函数
bit_cnt[i] = __builtin_popcount(i);
}
dp[0] = 1;
for(int j=1;j<End;j++){
dp[j] = 0;
double pp = 0;
for(int kk=0;kk<n;kk++){
if(j&(1<<kk)){
dp[j] += dp[j^(1<<kk)] * p[kk];
pp += p[kk];
}
}
//当前的dp[j]是第一次获得该集合的概率,答案需要的就是“第一次得到”的概率
if(bit_cnt[j] == k ){
for(int i=0;i<n;i++){
if(j&(1<<i)){
ans[i] += dp[j];
}
}
}
//根据等比数列求和公式,得到(在很长一段时间内)维持该集合的概率
dp[j] /= (1-pp);
}
int cnt = n;
for(int i=0;i<n;i++){
if(p[i] == 0){
cnt--;
}
}
if(cnt<k){
for(int i=0;i<n;i++){
printf("%.8f ", (p[i]==0.0)?0.0:1.0);
}
}else{
for(int i=0;i<n;i++){
printf("%.8f ",ans[i]);
}
}
return 0;
}