b276: 4和7 ---------DP

原题地址

DP妥妥的,看数据规模,首先需要离散化,其次转移的时间复杂度不能超过O(n^2),应当是O(n)左右

Point.1 某个规律

因为4和7互质,所以必然存在某个值k,使大于k的任意数都能分解为4和7的组合,手动模拟出这个数是18。理论上讲扩欧应该能够算出来。。。

Point.2 离散化

由于格子太多显然不能作为数组下标,但药堆数不大,所以读入时先储存下药粒数和位置信息,按位置排序。结合point.1,相邻两堆药之间的距离大于18时,实际上和等于18没差,因为后一个状态肯定能由前一个转移过来,所以重构格子序列,把所有大于18的间隔缩成18,这样就把格子编号缩到1800000范围内,就可以作为下标实现转移了。

Point.3 初始化

初始时f[i]一定要设成极小值,保证每次更新ans的f[i]都是已被更新过的,否则结果会比正解大;f[0]设为0,不然绝壁输出负数。

Point.4 转移

枚举每个位置(离散化后),f[i-4],f[i-7],f[i]取最大值。

参考代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
long long  a[1800005],f[1800005];
int n;
long long m,ans,x,y;
struct mc
{
	long long num,pos;
	bool operator <(const mc b) const
	{
		return pos<b.pos;
	}
}e[100005],p[100005];

void dp()
{
	long long st=0;
	for (int i=1;i<=n;i++)
		scanf("%d%lld",&e[i].num,&e[i].pos);
	sort(e+1,e+n+1);
	long long sx=0;
	e[0].num=0;
	e[0].pos=0;
	for (int i=1;i<=n;i++)
	{
		if (!(e[i].pos-e[i-1].pos))
		{
			a[st]+=e[i].num;
			continue;
		}
		if (e[i].pos-e[i-1].pos>=18)
		{
			st+=18;
			a[st]=e[i].num;
		}
		else
		{
			st+=e[i].pos-e[i-1].pos;
			a[st]=e[i].num;
		}
	}
	for (int i=1;i<=st;i++)
	{
		f[i]=-210000000;
		if (i>=4)
		    f[i]=max(f[i-4]+a[i],f[i]);
		if (i>=7)
		    f[i]=max(f[i-7]+a[i],f[i]);
		if (ans<f[i]) ans=f[i];
	}
	return;
}

int main()
{
	freopen("hop.in","r",stdin);
	freopen("hop.out","w",stdout);
	scanf("%d%lld",&n,&m);
	memset(a,0,sizeof(a));
	memset(f,0,sizeof(f));
	long long sy=0;
	dp();
	printf("%lld",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值