zoukankan      html  css  js  c++  java
  • [[HNOI2005]星际贸易]

    链接 [HNOI2005]星际贸易

    • 条件很多,其实是可以分开做的,有些条件在第一问,有些条件在第二问的。
    • 第一问没有限制,即最大化收益,(f_{i,j})表示前(i)个地点剩下(j)个东西没卖,背包即可。
    • 第二问基于第一问的选择,把第一问的转移扣出来即可,这里要最小化代价,设(g_{i,j})表示当前在(i)地点,燃料剩余(j)的最小花费,那么有:
    • [g_{i,j}=min(g_{i,j-1}+p_i) ]

    • 这是类似于多重背包的转移,也就是不停的在这里买燃料,因为从小往大更新的,所以省去了买多少的枚举复杂度。
    • [g_{i,j}=min(g_{k,j+2}+F_i) ]

    • 表示从别的地方过来,消耗两个燃料,然后修花费(F_i),注意这里满足(L leq Dis_i-Dis_k)(k)在最近一个必经点之后。
    • 直接转移复杂度(O(n^3)),发现维护前缀最小值,但是距离有限制,可以单调队列优化成(O(n^2))
    #include<bits/stdc++.h>
    #define R register int
    #define ll long long
    #define db double 
    using namespace std;
    const int N=4005;
    const int inf=2e9;
    int n,m,r,L,ans,pos,yes[N],f[N][N],pr[N][N],id[N];
    int tl[N],hd[N],G[N][N],a[N],b[N],l[N],P[N],F[N];
    int gi(){
    	R x=0,k=1;char c=getchar();
    	while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    	if(c=='-')k=-1,c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();	
    	return x*k;
    }
    int main(){
    	freopen("2.in","r",stdin);
    	n=gi(),m=gi(),r=min(2*n,gi()),L=gi();
    	for(R i=1;i<=n;++i)
    		a[i]=gi(),b[i]=gi(),l[i]=gi(),P[i]=gi(),F[i]=gi();
    	for(R i=1;i<n;++i)
    		if(l[i+1]-l[i]>L)return puts("Poor Coke!"),0;
    	memset(f,-63,sizeof(f)),f[0][m]=0;
    	for(R i=1;i<=n;++i){
    		for(R j=0;j<=m;++j)f[i][j]=f[i-1][j];
    		for(R j=0;j+a[i]<=m;++j)
    			f[i][j]=max(f[i][j],f[i-1][j+a[i]]+b[i]);
    	}
    	for(R j=0;j<=m;++j)if(f[n][j]>ans)ans=f[n][j],pos=j;
    	for(R i=n,j=pos;i>=1;--i){
    		if(f[i-1][j]==f[i][j])continue;
    		yes[i]=1,j+=a[i];
    	}
    	memset(f,63,sizeof(f)),f[0][r]=0,G[r][tl[r]++]=0;
    	for(R i=1;i<=n;++i)
    		for(R j=0;j<=r;++j){
    			if(j&&P[i])f[i][j]=min(f[i][j],f[i][j-1]+P[i]);
    			if(hd[j+2]<tl[j+2])f[i][j]=min(f[i][j],f[G[j+2][hd[j+2]]][j+2]+F[i]);
    			if(yes[i])hd[j]=tl[j]=0;
    			while(hd[j]<tl[j]&&f[i][j]<f[G[j][tl[j]-1]][j])tl[j]--;
    			G[j][tl[j]++]=i;
    			while(hd[j]<tl[j]&&l[i+1]-l[G[j][hd[j]]]>L)hd[j]++;
    		}
    	R res=f[0][0];
    	for(R j=0;j<=r;++j)res=min(res,f[n][j]);
    	if(res==f[0][0])puts("Poor Coke!");
    	else printf("%d %d
    ",ans,ans-res);
    	return 0;
    }
    
    
  • 相关阅读:
    深入理解JavaScript系列(45):代码复用模式(避免篇)
    深入理解JavaScript系列(38):设计模式之职责链模式
    深入理解JavaScript系列(43):设计模式之状态模式
    认识js中的function和this
    深入理解JavaScript系列(29):设计模式之装饰者模式
    javascript的内存分配
    详细解读Jquery各Ajax函数
    javascript 杂谈之哪种写法你更喜欢?
    深入理解JavaScript系列(28):设计模式之工厂模式
    深入理解JavaScript系列(30):设计模式之外观模式
  • 原文地址:https://www.cnblogs.com/Tyher/p/9845452.html
Copyright © 2011-2022 走看看