[ABC373F] Knapsack with Diminishing Values

AtCoder|Luogu|cnblogs

比较遗憾,E 题用了太多时间了,没做出来。当时看到有平方感觉难道是斜率优化之类的?这下猜对了。
拜谢 WA90。
不过官解好像没用斜率优化?不会。

\(f_{i,j}\) 表示前 \(i\) 个物品一共用了 \(j\) 的体积。直接暴力做是三次方的。

当加入一个体积为 \(w\),价值为 \(v\) 的物品时,就像单调队列优化多重背包一样,我们把 \(j\) 按照模 \(w\) 分组,只有组间会转移。设 \(g_k=f_{i-1,j}(j=d+kw)\),同样地设一个 \(h\) 对应新的 \(f_i\),那么就有转移:

\[h_i=\max_{j\le i}g_j+(i-j)v-(i-j)^2 \]

是我们喜欢的斜率优化。

\[j^2+jv-g_j=2ij+iv-h_i \]

\(f\) 还原就做完了。时间复杂度 \(\mathcal{O}(nW)\)

#include<bits/stdc++.h>
#define int long long
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(int i=(a);i>=(b);--i)
#define mp(a,b) make_pair(a,b)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define fi first
#define se second
#define eb emplace_back
#define ep emplace
#define pc __builtin_popcount
using namespace std;
typedef long long ll;
typedef double db;
const int N=3e3+5;
const int inf=0x3f3f3f3f;
const int INF=0x7f7f7f7f;
inline int read();
int n,m,k,W,w[N],v[N],f[N][N],g[N],q[N],l,r,I;
int X(int i){return i;}
int Y(int i){return i*i+i*v[I]-g[i];}
signed main()
{
n=read(),W=read();
FOR(i,1,n)w[i]=read(),v[i]=read();
FOR(id,1,n){
I=id;
memset(g,0,sizeof g);
FOR(d,0,w[id]-1){
int tmp=d;int tot=-1;
while(tmp<=W){
g[++tot]=f[id-1][tmp];
tmp+=w[id];
}
l=1,r=0;
FOR(i,0,tot){
while(l<r&&(Y(i)-Y(q[r]))*(X(q[r])-X(q[r-1]))<=(Y(q[r])-Y(q[r-1]))*(X(i)-X(q[r])))r--;
q[++r]=i;
while(l<r&&Y(q[l+1])-Y(q[l])<=2*i*(X(q[l+1])-X(q[l])))l++;
if(l<=r)f[id][d+i*w[id]]=g[q[l]]+i*v[id]-q[l]*v[id]-i*i-q[l]*q[l]+2*i*q[l];
}
}
}
FOR(i,1,W)f[n][i]=max(f[n][i],f[n][i-1]);
printf("%lld",f[n][W]);
return 0;
//あまりに短い夏だけで何を残していけるのかな?
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return f*x;
}
posted @   LHLeisus  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示