P2473
[SCOI2008] 奖励关
顺推转移存在不确定状态是否存在的问题,并不好做。
于是想到逆推。
定义
那么若对于状态
反之,则必须要保留:
最后答案即为
这里运用了一下滚动数组,但实际上每次还要赋初值,从常数的角度来说并不优,不如直接开大数组。
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll N=17;
ll n,k,x;
ll c[N+5];
double f[2][1<<N],p[N+5];
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}
int main() {
k=read();n=read();
for(ll i=1;i<=n;i++) {
scanf("%lf",&p[i]);
x=read();
while(x>0) {
c[i]|=(1<<(x-1));x=read();
}
}
for(ll i=k;i>=1;i--) {
for(ll j=0;j<(1<<n);j++) f[i&1][j]=0;
for(ll q=0;q<(1<<n);q++) {
for(ll j=1;j<=n;j++) if((q&c[j])==c[j]) {
f[i&1][q]+=max(f[1^(i&1)][q|(1<<(j-1))]+p[j],f[1^(i&1)][q]);
}
else {
f[i&1][q]+=f[1^(i&1)][q];
}
f[i&1][q]=f[i&1][q]/(double)n;
}
}
printf("%.6f",f[1][0]);
return 0;
}