https://ac.nowcoder.com/acm/contest/878/E
挺好的一道分组背包
byf跟我讲了以后我还以为是求一个期望然后得到他的代价,也就是必须要击落才能获得他的价值。(沟通还是有问题,我也总是想当然)
然而这题给了一个计算的公式,发射 Tij 枚 i 号导弹的时候有一个击中的概率Pij,而此时的价值是(Pij*W[i])四舍五入
byf的一句话提醒了我,发射一枚导弹的0.5<=p<1的概率击中,那么事实上Pij*W[i]的取值个数是log级别的个数,因为每多发一枚导弹,pij增速很快,而四舍五入就会导致取值个数很少。
那么我们可以预处理出对于(Pij*W[i])的每个取值,需要多少次发射,就可以得到他的代价
那么对于i号背包,可以看成一个背包组,里面有log个背包有不同的价值和代价
我们设f[j]为得到价值为 j 时,最小代价是多少
那么f[j]=min(f[j+1],f[i-c[i][k]]+w[i][k])
0<=j<=w1+w2+...+wn
总复杂度就是(nlogw*(w1+w2+..wn))
其实复杂度有点勉强,不过还是能过的。
#include<bits/stdc++.h>
#define maxl 510
using namespace std;
int n,m,num;
int a[maxl],w[maxl],c[maxl],f[maxl*maxl];
double r[maxl];
struct node
{
int w,c;
};
vector <node> q[maxl];
bool flag;
inline int rnd(double x)
{
return (int)(x+0.5);
}
inline void prework()
{
num=0;
for(int i=1;i<=n;i++)
scanf("%d",&w[i]),num+=w[i];
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&r[i]);
for(int i=1;i<=n;i++)
q[i].clear();
int ww,neww,t;double sum,tmp;
for(int i=1;i<=n;i++)
{
tmp=1;sum=r[i];t=1;
ww=rnd(sum*w[i]);
q[i].push_back(node{ww,t*c[i]});
tmp=tmp*(1.0-r[i]);
while(ww<w[i])
{
sum=sum+tmp*r[i];t++;
neww=rnd(sum*w[i]);
if(neww!=ww)
{
ww=neww;
q[i].push_back(node{ww,t*c[i]});
}
tmp=tmp*(1-r[i]);
}
}
}
inline void mainwork()
{
for(int i=1;i<=num+1;i++)
f[i]=2e9;
f[0]=0;
int l;
for(int i=1;i<=n;i++)
{
l=q[i].size();
for(int j=num;j>=0;j--)
{
f[j]=min(f[j],f[j+1]);
for(int k=0;k<l;k++)
if((j-q[i][k].w)>=0)
f[j]=min(f[j],f[j-q[i][k].w]+q[i][k].c);
}
}
}
inline void print()
{
int s;
for(int i=1;i<=m;i++)
{
scanf("%d",&s);
if(s>num || s<0 )
puts("Impossible");
else
printf("%d\n",f[s]);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}