走路 - dp

题目大意:
有n件物品,第 i i i件重量 a i a_i ai,坐标 i i i,若你现在身上有重量之和为w的物品,那么位移一个单位距离的代价是w+1。一开始你在0,最后要回到0,问花费代价不超过m的情况下,能够有的最大重量之和是多少。n<=1e5,m<=1e6.
题解:显然代价是两倍的最远距离加上每件物品代价是 i a i ia_i iai。这是个01背包,直接做显然是不行的,但是注意到代价关于收益的增长实际是非常快的(显然收益不会超过代价)因此设f(i,v)表示后i个物品,获得v的收益至少需要多少代价。注意到某个 k a k ≥ i a k ( k ≥ i ) ka_k\ge ia_k(k\ge i) kakiak(ki),因此 v &gt; m / i v&gt;m/i v>m/i的部分是不可能的,因此时间复杂度不超过调和级数。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;const int N=100010,M=1000010;int a[N],f[M];
int main()
{
    int n=inn(),m=inn();rep(i,1,m) f[i]=m+1;rep(i,1,n) a[i]=inn();
    for(int i=n;i;i--) if(a[i]<=m/i)
    {
        for(int j=m/i,v=i*a[i];j>a[i];j--) f[j]=min(f[j],f[j-a[i]]+v);
        f[a[i]]=min(f[a[i]],(i<<1)+i*a[i]);
    }
    for(int i=m;i;i--) if(f[i]<=m) return !printf("%d\n",i);return !printf("0\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值