C. Jump and Treasure(dp + 单调队列优化)

JSCPC

Problem

给出一个从0开始,长度为n+1一段序列,从1到n每个点上都有一定价值的金币a[i](可正可负)。从0号结点开始,每次可以跳跃不超过p个结点,跳到结点i上就(假设从i号结点跳到j号结点, i < j , j − i ≤ p i < j, j - i\leq p i<j,jip )。有q个询问,每次给出一个x( 1 ≤ x ≤ n 1 \leq x \leq n 1xn),问每次只能跳到x倍数的结点上(如果该结点编号小于n的话,只能跳到x的整数倍结点上。当跳到小于等于n的最后一个x的整数倍节点上时,只要最后一步跳出n,且这一步不超过p即可),同时,每次跳跃不能超过p,且最终必须跳到大于n的结点上:问多可以收集多少价值的金币。如果不能跳到大于n的结点上,则输出"Noob"。

Solution

  1. 状态表示:dp[i]表示跳到结点i上能够收集的最大价值的金币。
  2. 状态转移 d p [ i ] = m a x ( d p [ j ] ) + a [ i ]        ( i % x = 0 , j % x = 0 , i − j ≤ p ) dp[i] = max(dp[j]) + a[i]~~~~~~(i \% x = 0, j \% x = 0,i - j \leq p) dp[i]=max(dp[j])+a[i]      (i%x=0,j%x=0,ijp)
    可以用单调队列维护可以转移到状态i的几种状态。
  3. 注意:最终必须跳到大于n的节点上,最后一个状态应该是 n + 1,而不是最后一个x的整数倍节点上( n / x * x + x)。而且这两个状态不等价。
    例如: n = 10,p = 5, x = 2.
    当最后一种状态是 n + 1时(11),可以由 dp[6],dp[8],dp[10]中最大的一个转移过来。
    而,最后一种状态是 n / x * x + x时(12),可以由dp[8],dp[10]中最大的一个转移过来。
    显然,两种情况不等价,尤其需要注意。

Code

const int N = 2e6 + 6;
ll dp[N];
ll a[N];
unordered_map<ll, ll>mp;

int main()
{
	IOS;
	int n, q, p; cin >> n >> q >> p;
	for (int i = 1; i <= n; i++)
		cin >> a[i];

	while (q--)
	{
		deque<int> q;
		int x; cin >> x;

		if (mp.count(x))
		{
			cout << mp[x] << endl;
			continue;
		}

		if (x > p) cout << "Noob\n";
		else
		{
			dp[0] = 0;
			q.push_back(0);
			vector<int>b;
			b.push_back(0);
			for (int i = x; i <= n; i += x)
				b.push_back(i);
			b.push_back(n + 1);//注意:本题中n以内只能跳x的倍数,n以外可以不是x的倍数,所以不能写成n / x * x + x
			for (int i = 1; i < sz(b); i++)
			{
				while (q.empty() == 0 && b[i] - b[q.front()] > p) q.pop_front();
				dp[i] = dp[q.front()] + a[b[i]];
				while (q.empty() == 0 && dp[q.back()] <= dp[i]) q.pop_back();
				q.push_back(i);
			}

			mp[x] = dp[sz(b) - 1];
			cout << mp[x] << endl;
		}
	}

	return 0;
}

Tips

注意:要好好读题,这题最后一个状态尤其细节。。也至关重要

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

to cling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值