欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Loj#6039-「雅礼集训 2017 Day5」珠宝【四边形不等式,dp】

发布时间:2023/12/3 编程问答 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Loj#6039-「雅礼集训 2017 Day5」珠宝【四边形不等式,dp】 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

正题

题目链接:https://loj.ac/p/6039


题目大意

nnn个物品,第iii个费用为wiw_iwi,价值为viv_ivi,对于k∈[1,m]k\in[1,m]k[1,m]求费用为mmm时能获得的最大价值。

1≤n≤106,1≤m≤5×104,1≤wi≤300,1≤vi≤1091\leq n\leq 10^6,1\leq m\leq 5\times 10^4,1\leq w_i\leq 300,1\leq v_i\leq 10^91n106,1m5×104,1wi300,1vi109


解题思路

好早以前写的不过不知道为啥错了,现在来补个新的。

wiw_iwi很小,考虑以其为突破口,显然地我们可以把wiw_iwi相同的按照viv_ivi从大到小排序,那么对于每个wiw_iwi,我们就可以选择若干个。

fi,jf_{i,j}fi,j表示做到w=iw=iw=i时费用为jjj的最大价值和,那么有
fi,j=fi−1,j−ki+si,zf_{i,j}=f_{i-1,j-ki}+s_{i,z}fi,j=fi1,jki+si,z
si,zs_{i,z}si,z表示w=iw=iw=i的物品中前zzz大的价值和)

这个式子很难用常规的优化,但是可以用四边形不等式。至于证明,我们有wi,j=sj−iw_{i,j}=s_{j-i}wi,j=sji
要证明
wi,j+wi+1,j+1≥wi,j+1+wi+1,jw_{i,j}+w_{i+1,j+1}\geq w_{i,j+1}+w_{i+1,j}wi,j+wi+1,j+1wi,j+1+wi+1,j
sj−i+sj−i≥sj−i+1+sj−i−1s_{j-i}+s_{j-i}\geq s_{j-i+1}+s_{j-i-1}sji+sjisji+1+sji1
然后因为si+1−sis_{i+1}-s_{i}si+1si是递减的,所以成立。

那么我们现在对于每个枚举的w=iw=iw=i,把所有的ik+j(j∈[0,i))ik+j(\ j\in[0,i)\ )ik+j( j[0,i) )都分成一组。

然后对于每一组我们都用四边形不等式优化,不过我忘了优化的方法了,还是记一下吧:

对于所有的可能的决策我们用一个单调队列记录,顺带记录ziz_izi表示队列里第iii个决策和第i+1i+1i+1个决策的交叉点(在ziz_izi之前qiq_{i}qi更优,ziz_izi以之后qi+1q_{i+1}qi+1更优)。

然后每次弹出队列前面的来找答案,加入的时候我们就二分出队尾和新加入的决策交换点,然后一直弹尾部直到不交叉。

时间复杂度:O(mwlog⁡m)O(mw\log m)O(mwlogm)


code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const ll N=5e4+10; ll n,m,g,f[2][N],q[N],z[N]; vector<ll> w[310]; bool cmp(ll x,ll y) {return x>y;} ll calc(ll i,ll j,ll p,ll k) {return f[!g][i*p+k]+w[p][j-i-1];} ll bound(ll i,ll j,ll p,ll k){ll l=i+1,r=(m-k)/p;while(l<=r){ll mid=(l+r)>>1;if(calc(i,mid,p,k)<calc(j,mid,p,k))l=mid+1;else r=mid-1;}return l; } signed main() {freopen("jewelry.in","r",stdin);freopen("jewelry.out","w",stdout); scanf("%lld%lld",&n,&m);for(ll i=1,c,v;i<=n;i++){scanf("%lld%lld",&c,&v);w[c].push_back(v);}g=0;for(ll p=1;p<=300;p++){if(w[p].empty())continue;g^=1;memcpy(f[g],f[!g],sizeof(f[g])); // memset(f[g],0,sizeof(f[g]));sort(w[p].begin(),w[p].end(),cmp);while(w[p].size()<=m/p)w[p].push_back(0);for(ll i=1;i<w[p].size();i++)w[p][i]+=w[p][i-1];for(ll k=0;k<p;k++){ll head=1,tail=0;for(ll i=0;i*p+k<=m;i++){while(head<tail&&z[head]<=i)head++;if(head<=tail)f[g][i*p+k]=max(f[g][i*p+k],calc(q[head],i,p,k));while(head<tail&&z[tail-1]>=bound(i,q[tail],p,k))tail--;z[tail]=bound(i,q[tail],p,k);q[++tail]=i;}}}for(ll i=1;i<=m;i++)printf("%lld ",f[g][i]);return 0; }

总结

以上是生活随笔为你收集整理的Loj#6039-「雅礼集训 2017 Day5」珠宝【四边形不等式,dp】的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。