首页 > 其他分享 >[HNOI2005] 星际贸易 题解

[HNOI2005] 星际贸易 题解

时间:2024-04-25 09:55:40浏览次数:15  
标签:head int 题解 tail HNOI2005 res 星际 星球 dp

[HNOI2005] 星际贸易

将问题分为两次 dp。

题面有:“只有一种获得最大贸易额的方法”

所以直接说明了贸易额与那些费用无关。

有考虑到无论干啥都要维护,第二次 \(dp\) 直接以暗物质为核心即可

对于这里 \(R\) 与 \(n*2\) 取 \(min\) 的一些细节理解。

我们设计状态,因为观察到了暗物质最多也就使用 \(n*2\) 个,与 \(R\) 如此之大的范围无关

第二次 \(dp\) 中,\(f_{i,j}\) 表示到了第 \(i\) 颗星球,还有 \(j\) 暗物质的最小花费

正确性:

  • \(r > n*2\) 时,直接不买

  • \(r \le n*2\) 时,做 \(dp\),由大于 \(n*2\) 的位置转移过来是不合法的

对于第二次 dp 中,要进行销售的星球与要买暗物质的星球的维护费用冲突的解决

对于考虑暗物质是建立在确定了那些是要销售的星球的基础上的,所以第二次 \(dp\) 对于这些星球的维护费用不应该考虑。

由于我们用单调队列模拟这个滑动窗口的过程,当跑到被选为要销售的星球时,直接 \(head[j] = tail[j] = 0\)。

所以这里 \(dp\) 可以理解为在每两颗被选星球中间做选择。

CODE

#include<bits/stdc++.h>
#define print(a) cout<<#a"="<<(a)<<endl
#define debug() cout<<"Line:"<<__LINE__<<endl
#define sign() puts("-------")
#define inf 0x3f3f3f3f
using namespace std;
const int N = 2010;
int n,m,r,L0;
int ans1,ans2;
bool mark[N];
int dp[N][N];
struct Star{ int goal,val,dis,price,cost; }a[N];
void DP(){
	memset(dp,-1,sizeof dp);
	dp[0][0] = 0;
	for(int i = 1;i<=n;++i)
		for(int j = 0;j<=m;++j){
			if(dp[i-1][j] >= 0)dp[i][j] = dp[i-1][j];
			if(j >= a[i].goal && dp[i-1][j-a[i].goal] >= 0)
				dp[i][j] = max(dp[i-1][j-a[i].goal] + a[i].val,dp[i][j]);
		}
	int res = 0;
	for(int i = 0;i<=m;++i){
//		print(dp[n][i]);
		if(dp[n][i] > dp[n][res])res = i;
	}
	for(int i = n,j = res;i;--i){
		if(dp[i][j] == dp[i-1][j])continue;
		else mark[i] = 1, j -= a[i].goal;
	}
//	print(res);
	ans1 = dp[n][res];
}
int f[N][N];
int tail[N],q[N][N],head[N];
void solve(){
	memset(f,0x3f,sizeof f);
	f[0][r] = 0;
	q[r][++tail[r]] = 0;
	for(int i = 1;i<=n;++i){
		for(int j = 0;j<=r;++j){
			if(a[i].price && j)f[i][j] = min(f[i][j],f[i][j-1] + a[i].price);
			if(tail[j+2] > head[j+2])f[i][j] = min(f[i][j],f[q[j+2][head[j+2]]][j+2] + a[i].cost);
			if(mark[i])head[j] = tail[j] = 0;
			while(head[j] < tail[j] && f[q[j][tail[j]-1]][j] >= f[i][j])--tail[j];
			q[j][tail[j]++] = i;
			while(head[j] < tail[j] && a[i+1].dis - a[q[j][head[j]]].dis > L0)++head[j];
		}
	}
	int res = 0;
	for(int i = 0;i<=r;++i)if(f[n][i] < f[n][res])res = i;
	if(f[n][res] == inf)puts("Poor Coke!");
	else printf("%d %d",ans1,ans1-f[n][res]);
}
int main(){
	scanf("%d%d%d%d",&n,&m,&r,&L0);
	r = min(r,n<<1);
	a[0] = {0,0,0,0,0};
	for(int i = 1;i<=n;++i)
		scanf("%d%d%d%d%d",&a[i].goal,&a[i].val,&a[i].dis,&a[i].price,&a[i].cost);
	for(int i = 1;i<=n;++i)if(a[i].dis - a[i-1].dis > L0)return puts("Poor Coke!"),0;
	DP();
	solve();
	return 0;
}

标签:head,int,题解,tail,HNOI2005,res,星际,星球,dp
From: https://www.cnblogs.com/fight-for-humanity/p/18156939

相关文章

  • 洛谷 P8989 [北大集训 2021] 随机游走 题解
    前言又是随机游走?题目分析看到加边,可能性太多了。但是为了让步数最大化,我们可以贪心地想,肯定要往前面连,而且越前面要走的期望步数肯定越大。并且,我们不会浪费边在终点上。于是,题目转变成了\(1\simn-1\)连向起点\(1\)连若干条边,使得随机游走到终点的期望步数最大。那要......
  • [题解]P5431 【模板】模意义下的乘法逆元 2
    可恶,卡常好难受。P5431【模板】模意义下的乘法逆元2将分数通分,第\(i\)个分数是\(\frac{k^i*fac\diva[i]}{fac}\),\(fac\)表示所有元素的积。我们可以用\(lr,rl\)记录\(a\)的前缀后缀积,第\(i\)个分数就是\(\frac{k^i*lr[i-1]*rl[i+1]}{lr[n]}\)。这样分母都是\(lr[n]\),分子就......
  • qoj3082 Ascending Matrix 题解
    题目链接点击打开链接题目解法不考虑第\(a_{r,c}=v\)的限制怎么求?我们把条件形式化一下,发现\(k\)个区域的颜色可以表示成轮廓线的形式,即第\(i-1\)条到第\(i\)条轮廓线之间的格点颜色为\(i\)问题变成找到\(k-1\)条互不穿过的路径,起点为\((1,m)\),终点为\((n,1)\)......
  • P2882 题解
    思想一眼看上去,没什么思路。看一下标签。枚举!于是枚举\(K\)。然后变成了求最少次数。由于枚举放在第一个,我们还是考虑一下枚举。我们枚举反转区间的左端点,我们惊奇地发现,由于从左往右扫,如果左端点是朝后的,那这次不转就没机会了。所以最最简单的暴力:从左往右扫,遇到左端点......
  • 「洛谷」题解:P1217 回文质数
    题目传送门看着题目好像很简单的样子,实际上做起来才会发现,这么多函数他奶奶的是普及-难度?在这道题目当中,我们最少需要写两个函数,如果需要优化可以再多写一个,待会儿的代码我们就直接放最简单版本的了。有人说这道题可以暴力对拍之后再输出,这完全可以,但是这么简单的题目不至于使用......
  • 2022ccpc题解
    2023年第五届河南省CCPC大学生程序设计竞赛ProblemA.Mocha上小班啦思路:求n个数位的最小值,条件:每一位数字都不同切不含前导零。只需要把0放到第二位,其他按从小到大输出,大于10以后输出-1即可。#include<bits/stdc++.h>usingnamespacestd;intmain(){//预处......
  • P5900 无标号无根树计数 题解
    不懂为啥都要对原式神秘转化之后再牛顿迭代,直接对原式牛顿迭代即可!完全不用转化!设无标号有根树的组合类是\(\mathcalT\),则有\(\mathcalT=\mathcalZ\times\mathrm{MSET}(\mathcalT)\),即\(T(x)=x\exp\sum\limits_{j\ge1}\dfrac{T(x^j)}j\),设\(G(F(x))=F(x)-x\exp\sum\lim......
  • abc340E题解
    题目描述样例input:5312345240output:04272算法1(树状数组)$O(nlogn)$本题我们可以看作对于每一个查询位置x我们都需要先把该位置上的所有球拿出来,然后再一个一个的放到对应位置上去。假设x位置上面有y个球,那么对于这y个球,如果大于n,那么就对所有的位置放y......
  • P3667 Bovine Genomics Hash+二分题解
    砂金听说了你在学字符串,于是在CLOI里出了道题给你P3667BovineGenomics题链:洛谷hzoi提高\(hash\)基础题。思路是二分答案,\(check\)中比较每一个区间字串的\(hash\)值是否相等。比较的时候可以用\(set\)或\(map\)。\(set\)的好处在于无重元素,判断时先将\(a\)串中区间子串......
  • 抢先看!美团、京东、360等大厂面试题解析,技术面试必备。
    技术面试必备!美团、京东、360等大厂面试题详解,让你轻松应对各大公司面试挑战!往期硬核面经哦耶!冲进腾讯了!牛逼!上岸腾讯互娱和腾讯TEG!腾讯的面试,强度拉满!前几篇文章分享了上岸腾讯的最新面经。不少粉丝股东留言说别只发腾讯的啦,其他大厂的也安排一些吧,比如美团、360、京东的......