我没有想到怎么dp,怕是完了。。。(啊,只拿了5分。。。)
首先我们能发现
假设前面一个怪物为x1,y1后面一个怪物为x2,y2我们怎么确定如果两个怪物都要打先打前面那个?
列个式子如果前面一个先打前面一个耗费x1*y1+ad(x1+y1)+a^2*d^2后面一个则为x2*y2+bd(x2+y2)+b^2*d^2(a<b)因为最后所消耗的代价是它们的和所以可以发现区别就在x+y上,
我们只需要排个序将x+y从大到小排,然后用一个dp求出要在前j只怪物中选择i只怪物解决的时所需要的最小的生命值花费(这个就是背包吧。。。)
然后输进一个猎人的生命值再二分就可以了。
我很二地认为只要排过序后顺次取就可以了(然而并不能证明)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stack> #include<cstdlib> using namespace std; typedef long long ll; struct ding{ll a,b; }x[3009]; int n,m; ll d,dp[3009][3009],maxx; bool cmp(ding x,ding y) {return x.a+x.b>y.a+y.b; } inline int read() {char ch;ll ex=0;while ((ch<'0')||(ch>'9')) ch=getchar();while ((ch>='0')&&(ch<='9')) {ex=ex*10+ch-'0';ch=getchar();}return ex; } int check(ll p) {int l=1,r=n,tot=0;while (l<=r){int mid=(l+r)>>1;if (p<=dp[mid][n]) r=mid-1;else l=mid+1,tot=mid;}return tot; } int main() {scanf("%d%d",&n,&m);d=read();for (int i=1;i<=n;i++) x[i].a=read();for (int i=1;i<=n;i++) x[i].b=read();sort(x+1,x+1+n,cmp);for (int i=1;i<=n;i++)for (int j=i;j<=n;j++){ll pum=dp[i-1][j-1]+x[j].a*x[j].b+(i-1)*d*(x[j].a+x[j].b)+(i-1)*(i-1)*d*d;if (j!=i) dp[i][j]=min(pum,dp[i][j-1]);else dp[i][j]=pum;}for (int i=1;i<=m;i++) {ll h;scanf("%lld",&h);printf("%d ",check(h));}return 0; }