1 条题解
-
0
自动搬运
来自洛谷,原作者为

Unknown_Error
OI(2014-2018)搬运于
2025-08-24 22:01:10,当前版本为作者最后更新于2018-05-07 21:46:01,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先先考虑朴素dp,设f[i][j]为到了第i家店,1~i-1家店共买了j吨饲料
那么转移可以写成 :
f[i][j]=min(f[i][j],f[i-1][k]+jjd[i]+(j-k)*a[i-1].w); 其中a[i-1].w为第i-1家店饲料的价格,d[i]为第i与i-1家店的距离 复杂度为O(nk^2),很明显炸了
怎么办??
先把式子拆了吧
f[i][j]=min(f[i][j],f[i-1][k]+jjd[i]+ja[i-1].w-ka[i-1].w)
提出来f[i-1][k]+jjd[i]+ja[i-1].w-ka[i-1].w
把属于k的提出来,变为f[i-1][k]-ka[i-1].w+jjd[i]+ja[i-1].w
可以发现,后半部分是定值,我们用单调队列维护前半部分就好了 但是如果单纯的单调队列会错,为啥?如果我这家店所能提供的饲料不够我需要的呢?
所以,还要加上几个特判啦
代码
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL inf=1e15; struct node { LL x,c,w;//距离 数量 价格 }a[11000]; bool cmp(node n1,node n2){return n1.x<n2.x;} LL f[510][11100];//第i家店 1~i-1家店装了j吨饲料 int n,m,kk;//n家店 距离m 希望买kk LL d[11000]; LL list[11000],head,tail; int main() { //freopen("feed.in","r",stdin); //freopen("feed.out","w",stdout); scanf("%d%d%d",&kk,&m,&n); for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i].x,&a[i].c,&a[i].w); n++;a[n].x=m; sort(a+1,a+1+n,cmp); for(int i=2;i<=n;i++)d[i]=a[i].x-a[i-1].x; for(int i=0;i<=n;i++)for(int j=0;j<=kk;j++)f[i][j]=inf; f[0][0]=0; for(LL i=1;i<=n;i++) { head=tail=0; for(LL j=0;j<=kk;j++) { while(head<tail && j-list[head]>a[i-1].c)head++;//需要买的 本商店不能满足 if(f[i-1][j]!=inf) { while(head<tail) { LL k=list[tail-1]; if(f[i-1][k]-k*a[i-1].w<f[i-1][j]-j*a[i-1].w)break; tail--; } list[tail++]=j; } if(head<tail) { LL k=list[head]; f[i][j]=f[i-1][k]+(j-k)*a[i-1].w+j*j*d[i]; } } } printf("%lld\n",f[n][kk]); return 0; }
- 1
信息
- ID
- 3519
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者