题解:
预处理一个
f
i
,
j
f_{i,j}
fi,j表示有
i
i
i个钻石,购买了
j
j
j个物品所需要的最小费用,然后就可以愉快的折半了。
#include <bits/stdc++.h>
using namespace std;
typedef pair <int,double> pid;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=32, inf=1e9;
int n,m,mid,f[N][N],v[N],c[N],d[N]; double p[N],ans;
vector <pid> q[N];
vector <double> s[N];
inline void dfs1(int i,int nn,int c1,int c2,double t) {
if(i==nn+1) {q[c2].push_back(pid(c1,t)); return;}
dfs1(i+1,nn,c1,c2+1,t*(1-p[i]));
dfs1(i+1,nn,c1+v[i],c2,t*p[i]);
}
inline void dfs2(int i,int nn,int c1,int c2,double t) {
if(i==nn+1) {
for(int j=0;j<=mid;j++) {
int lst=0;
for(int k=0;k<=m;k++) {
int p=lower_bound(q[j].begin(),q[j].end(),(k==m) ? pid(inf,inf) : pid(f[c2+j][k+1]-c1,0))-q[j].begin()-1;
if(~p) ans+=(s[j][p]-(lst ? s[j][lst-1] : 0))*t*k; lst=p+1;
if(lst==q[j].size()) break;
}
} return;
}
dfs2(i+1,nn,c1,c2+1,t*(1-p[i]));
dfs2(i+1,nn,c1+v[i],c2,t*p[i]);
}
inline void solve() {
n=rd(), m=rd(); ans=0;
for(int i=1;i<=n;i++) v[i]=rd(), p[i]=(double)rd()/100;
for(int i=1;i<=m;i++) c[i]=rd(), d[i]=rd();
for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) f[i][j]=inf;
f[0][0]=0;
for(int i=1;i<=m;i++)
for(int j=n;j>=d[i];j--)
for(int k=i;k>=1;k--)
f[j][k]=min(f[j][k],f[j-d[i]][k-1]+c[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j]=min(f[i][j],f[i-1][j]);
mid=min(18,n);
for(int i=1;i<=mid;i++) q[i].clear(); for(int i=1;i<=mid;i++) q[i].clear();
dfs1(1,mid,0,0,1);
for(int i=0;i<=mid;i++) {
sort(q[i].begin(),q[i].end());
s[i].assign(q[i].size(),0);
for(int j=0;j<q[i].size();j++) s[i][j]=q[i][j].second+(j?s[i][j-1]:0);
}
dfs2(mid+1,n,0,0,1);
printf("%.4f\n",ans);
}
int main() {
for(int T=rd();T;T--) solve();
}