codeforces698C. LRU
分析
題目大意:給你一個初始爲空的隊列和個數,每一輪每個數有的概率被選中。如果這個數不在隊列中就把它放到隊尾,否則什麼都不會發生。如果當前隊列大小,就把隊首彈出去。求操作之後每個數出現的概率。
考慮某個數在隊列的情況,那麼在其之後的放的數的種類不能超過
如果我確定了出現的數
令
那麼每一個數可出現與可不出現的概率就是
那麼對於一個數,求先出現一個
答案就是
但是由於這個概率包括了出現和不出現的情況,而我們要求的是大小爲的所有集合的答案,所以要容斥。
大小爲的集合會被它的所有超集重複枚舉一次,所以容斥係數就是
其中表示的大小爲的超集個數。
代碼
#include<bits/stdc++.h>
const int N = 1 << 20;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int c[22][22], pw[22], cnt[N], n, k;
double u[22], p[22], sum[N];
int main() {
n = ri(); k = ri();
pw[0] = 1;
for(int i = 1;i <= n; ++i)
pw[i] = pw[i - 1] << 1;
for(int i = 0;i < n; ++i)
scanf("%lf", &p[i]), sum[pw[i]] = p[i];
c[0][0] = 1;
for(int i = 1;i <= n; c[i++][0] = 1)
for(int j = 1;j <= i; ++j)
c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
for(int s = 1;s < pw[n]; ++s)
sum[s] = sum[s ^ (s&-s)] + sum[s&-s], cnt[s] = cnt[s >> 1] + (s & 1);
for(int i = k - 1; ~i; --i) {
u[i] = 1;
for(int j = i + 1; j < k; ++j)
u[i] -= u[j] * c[n - 1 - i][j - i];
}
for(int i = 0;i < n; ++i) {
if(!p[i] || p[i] == 1 || k == 1) {printf("%.9lf ", p[i]); continue;}
double ans = 0;
for(int s = 0;s < pw[n]; ++s)
if((~s & pw[i]) && cnt[s] < k)
ans += u[cnt[s]] / (1 - sum[s]);
printf("%.9lf ", p[i] * ans);
}
return 0;
}