NOIP2018D1T1题解

NOIP2018D1T1题解

先来自我介绍一下,本人是只初三的蒟蒻,第一次在CDSN上面发博客鸭,还请诸位多多指教。然后因为本人智商极低,再加上弱到不行,所以题解可能会非常非常的直白易懂。估计没学过c++的,学过数学的都看的懂orz……

进入正题:noip考完了,不出意外,提高组差点爆零qwq……只AC了D1T1…… 做出来的过程也非常的曲折离奇,惊天地泣鬼神emm 前面刚看到题的时候觉得T1是一道dp/线段树的题,应该不会太水,然后就先去做了T3(因为第一次考提高组,这次考试的目标就是能骗到一分是一分,所以一看T3能写一个非常弱的程序拿部分分就写了)然后因为实在太弱了,所以T3写了好久好久。写T1的时候就不剩多少时间了,觉得自己肯定没时间写个线段树什么的正解了,就打算手推一下,能拿一分拿一分。结果推着推着就推对了!!!鸡冻٩(๑>◡<๑)۶总算是还A了一道。

题目
(这只是我记忆中的题目,和真实的会有所出入,大家凑活看看)
大概就是一个人,他要填坑,然后他每次选路的一段把它们整体填1的深度。但是他有个条件,就是这段路中不能有大于等于0的部分。然后给你一条路,问你他最少用多少次才能把这段路填成都是0。
Day1的题目在下面,请叫我小天使,谢谢O…O
https://wenku.baidu.com/view/d1f022472379168884868762caaedd3383c4b5d9.html

样例
我记得它题目中给的是4 3 2 5 3 5鸭

思路
我们来思考一下:他既然要填坑,还要填的最快,那最优秀的方法肯定就是第一次把整个路都填1,直到填到不能再填为止。然后接下来从头开始选一段可填的路填填填填填填填填填(感觉填这个字都不像字了……),填到不能再填,以此类推……
上述方法肯定最优,不接受反驳!我们把上面的这个思路换一个角度重现一下。可以想成第一次这个人只填这个坑,但是他可以捎带手填后面的所有坑,直到填不了。
拿样例举个例子,把它想成先填第一个“4”,同时它捎带手填了后面的几个,它捎带手能填的坑有什么条件呐?就是比它前面的坑要浅。这样能一直填到第四个数,这时候它填不完它了,只能给它填2。然后我们就从它开始填(这时候它已经被我们第一个4捎带手填成了3),以此类推,自行理解bia(应该已经很清楚了鸭,比网上绝大多数大佬都要清楚鸭qwq)

代码
代码如下(www.student.gov.cn出代码了,这个是当时我考场上的代码)

#include 
#include 
#include 
#include 
#include 
using namespace std ;
int n ;
long long cnt ;
int d[100001] ;
int main ()
{
	ios::sync_with_stdio(false) ;
	freopen ( "road.in" , "r" , stdin ) ;
	freopen ( "road.out", "w" , stdout) ;
	cin >> n ;
	for ( int i = 1 ; i <= n ; i++ )
		cin >> d[i] ;
	
	cnt = d[1] ;
	for ( int i = 2 ; i <= n ; i++ )
	{
		if ( d[i] <= d[i-1] )
			continue ;
		else
			cnt += d[i] -d[i-1] ;
	}
	cout << cnt << endl ;
	return 0 ;
}

然后我决定再不要脸的附上网站上找到的同校大佬考场上写的线段树AC代码(未获得版权 ,所以祈祷千万别被他看见啊……)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int MAXN = 100005;

int n,ans;
int a[MAXN];
int sum[MAXN];
int L[MAXN];
int R[MAXN];
int val[MAXN];
int laz[MAXN << 2];

priority_queue > Q;

void pushdown(int o)
{
	if (laz[o] != -1)
	{
		laz[o << 1] = laz[o];
		laz[o << 1 | 1] = laz[o];
		laz[o] = -1;
	}
}

void buildtree(int o,int l,int r)
{
	laz[o] = -1;
	if (l == r)
	{
		laz[o] = l;
		return;
	}
	int mid = (l + r) >> 1;
	buildtree(o << 1,l,mid);
	buildtree(o << 1 | 1,mid + 1,r);
}

void setv(int o,int l,int r,int x,int y,int v)
{
	if (l >= x && r <= y)
	{
		laz[o] = v;
		return;
	}
	pushdown(o);
	int mid = (l + r) >> 1;
	if (mid >= x)
		setv(o << 1,l,mid,x,y,v);
	if (mid + 1 <= y)
		setv(o << 1 | 1,mid + 1,r,x,y,v);
}

int belong(int o,int l,int r,int p)
{
	if (l == r)
		return laz[o];
	pushdown(o);
	int mid = (l + r) >> 1;
	if (mid >= p)
		return belong(o << 1,l,mid,p);
	return belong(o << 1 | 1,mid + 1,r,p);
}

int main()
{
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	scanf("%d",&n);
	for (int i = 1;i <= n;i++)
	{
		scanf("%d",&a[i]);
		L[i] = i;
		R[i] = i;
		val[i] = a[i];
		Q.push(make_pair(a[i],i));
	}
	buildtree(1,0,n + 1);
	for (int i = 1;i <= n;i++)
	{
		int cur = Q.top().second,v = Q.top().first;
		Q.pop();
		int id = belong(1,0,n + 1,cur);
		if (val[id] != v)
			continue;
		int Lv = belong(1,0,n + 1,L[id] - 1),Rv = belong(1,0,n + 1,R[id] + 1);
		int to = max(val[Lv],val[Rv]);
		ans += val[id] - to;
		if (to == val[Lv])
			L[id] = L[Lv];
		if (to == val[Rv])
			R[id] = R[Rv];
		setv(1,0,n + 1,L[id],R[id],id);
		val[id] = to;
	}
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(详细题解)