ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1131G Most Dangerous Shark

2021-07-14 11:04:22  阅读:206  来源: 互联网

标签:Shark qr int Dangerous st Most 骨牌 推倒 dp


一、题目

点此看题

二、解法

考虑每个点的推倒状态只有向左倒和向右倒,然后我们又要把所有骨牌推倒,所以设计 \(dp[i]\) 表示推倒前 \(i\) 个骨牌的最小代价,假设我们会处理 \(l[i],r[i]\) 表示向左推倒骨牌 \(i\) 覆盖的左端点,向右推倒骨牌 \(i\) 覆盖的右端点,转移:

  • 把 \(i\) 向左推倒:\(dp[i]=dp[j]+c[i] \ \ \ \ \ l[i]-1\leq j<i\)

  • 把 \(j\) 向右推倒:\(dp[i]=dp[j-1]+c[j] \ \ \ \ \ j<i\leq r[j]\)

第一种转移其实只需要考虑 \(j=l[i]-1\) 时的转移即可,因为 \([l[i],i]\) 的骨牌 \(i\) 能推倒就不需要前面去管了。第二种转移看似需要线段树优化,做到 \(O(n)\) 我们需要观察性质。

不难发现每个骨牌的覆盖范围要么包含,要么相离,所以可以维护一个栈,每次新加入的点就放在栈顶,每次只需要考虑栈顶得覆盖范围够不够,不够直接弹出,然后维护一个栈的前缀最小值就可以转移了。

现在的问题是算 \(l[i],r[i]\),就说 \(l[i]\) 怎么算吧,还是维护一个栈,首先弹出没有用的点,也就是 \(i-h[i]\leq tp-h[tp]\),并且栈顶对于以后的元素也没有用了。然后我们考虑当前点能不能覆盖到栈顶,如果不能的话就直接用 \(i-h[i]+1\),如果可以的话就用 \(l[tp]\),不难发现他是最优的。

三、总结

考虑每个点的状态有哪些,然后 \(dp\),只要涉及了所有状态就可以。

\(dp\) 的线性优化可以考虑找性质,然后用单调数据结构维护该性质。

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
const int M = 10000005;
const int N = 250005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,q,h[M],c[M],f[M],l[M],r[M],st[M],mn[M];
vector<int> a[N],b[N];
signed main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		int k=read();
		for(int j=1;j<=k;j++) a[i].push_back(read());
		for(int j=1;j<=k;j++) b[i].push_back(read());
	}
	q=read();n=0;
	while(q--)
	{
		int id=read(),ml=read();
		for(int i=0;i<a[id].size();i++)
			h[++n]=a[id][i],c[n]=b[id][i]*ml;
	}
	int qr=0;
	for(int i=1;i<=n;i++)
	{
		while(qr && i-h[i]<=st[qr]-h[st[qr]]) qr--;//useless
		if(!qr || i-h[i]>=st[qr]) l[i]=max(i-h[i]+1,1ll);
		else l[i]=l[st[qr]];
		st[++qr]=i;
	}
	qr=0;
	for(int i=n;i>=1;i--)
	{
		while(qr && i+h[i]>=st[qr]+h[st[qr]]) qr--;
		if(!qr || i+h[i]<=st[qr]) r[i]=min(i+h[i]-1,m);
		else r[i]=r[st[qr]];
		st[++qr]=i;
	}
	qr=0;mn[0]=1e18;
	for(int i=1;i<=n;i++)
	{
		while(qr && r[st[qr]]==i-1) qr--;//illegal
		f[i]=f[l[i]-1]+c[i];
		if(qr) f[i]=min(f[i],mn[qr]);
		st[++qr]=i;mn[qr]=min(mn[qr-1],f[i-1]+c[i]);
	}
	printf("%lld\n",f[n]);
}

标签:Shark,qr,int,Dangerous,st,Most,骨牌,推倒,dp
来源: https://www.cnblogs.com/C202044zxy/p/15009805.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有