小奇挖矿 2 题解

版权声明:八月炊火的博客如需转载请注明出处 https://blog.csdn.net/qq_34990731/article/details/83188149

小奇挖矿 2
题目:
题目背景:
小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎。
问题描述:
现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球。
有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上。由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量。注意,小奇不必最终到达m号星球。
输入格式:
第一行2个整数n,m。
接下来n行,每行2个整数ai,bi。
输出格式:
输出一行一个整数,表示要求的结果。
样例输入:
3 13
100 4
10 7
1 11
样例输出:
101
样例解释:
第一次从0到4,第二次从4到11,总共采到101单位原矿。
数据范围:
对于20%的数据 n=1,m<=10^5
对于40%的数据 n<=15,m<=10^5
对于60%的数据 m<=10^5
对于100%的数据 n<=105,m<=109,1<=ai<=10^4,1<=bi<=m

知识点: DP、一个类似于离散化的东西

讲解:
这一题想必大家都可以拿到60分 (然而博主才20分 ),先将一下60分的思路,我们采用DP,我们定义DP[i]表示到i这个星球可以获得的最大原矿,很容易相处状态转移方程,DP[i]=max(DP[i-4],DP[i-7])+a[i],a[i]表示i这个星球可以获得的原矿数目。现在唯一的问题就是MLE,因为m的值太大所以我们会炸,想一下怎么解决,我们可以采用离散化(然而我不知道这是不是离散化,没学过不过感觉很像),我们可以发现n<=100000,我们考虑从n入手,可是转移的过程又和m有关,我们发现如果两个星球之间的距离可以分解成几个4相乘加几个7相乘那么这样就可以转移,我们通过计算发现在所有数中只有1 2 3 5 6 9 10 13 17这几个不可以,所以我们特判一下。思路就是我们把所有距离大于17(没有等于)的全部看成相距18,那么这样距离就大大被我们缩短了,我们就可以正常DP了。
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct kuang
{
	int a,b;
}ac[100100];
bool cmp(const kuang x,const kuang y)
{
	return x.b<y.b;
}
int dp[2000100],much[2000100];
int main()
{
	int n,m,ans=0,now=0;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)//读入数据 
	{
		int x,y;
		scanf("%d %d",&ac[i].a,&ac[i].b);
	}
	sort(ac+1,ac+1+n,cmp);//我们排序一下确保星球按照位置排序,方便我们后面处理 
	for(int i=1;i<=n;i++)
	{
		if(ac[i].b-ac[i-1].b>17)//判断一下这一个与前一个的距离 
			now+=18,much[now]+=ac[i].a;//大于17一律看成18,我们用much数组记录我们压缩后路径上对应位置上的原矿,now则是压缩后的总路径 
		else now+=ac[i].b-ac[i-1].b,much[now]+=ac[i].a;//否则就按照实际距离计算 
	}
	for(int i=1;i<=now;i++)//全部初始化 
		dp[i]=-1;
	for(int i=0;i<=now;i++)
	{
		if(dp[i]==-1)//如果我们这个点都不可以到达就跳过 
			continue;
		dp[i+4]=max(dp[i+4],dp[i]+much[i+4]);//否则用它来更新其他的 
		dp[i+7]=max(dp[i+7],dp[i]+much[i+7]);
		ans=max(ans,dp[i]);//因为可以随时停下所以我们随时记录最大值 
	}
	printf("%d",ans);//输出答案 
	return 0;
}

希望大家都可以AC。

猜你喜欢

转载自blog.csdn.net/qq_34990731/article/details/83188149