首页 > 其他分享 >【POI2011】Lightning Conductor_【JSOI2016】灯塔(决策单调性优化dp)

【POI2011】Lightning Conductor_【JSOI2016】灯塔(决策单调性优化dp)

时间:2022-10-29 11:36:24浏览次数:56  
标签:Conductor JSOI2016 max POI2011 mid gety tail ans 函数

首先进行变形:

\[\begin{aligned} a_j&\leq a_i+p-\sqrt{|i-j|}\\ p&\geq \max_{j=1}^n\left(a_j+\sqrt{|i-j|}\right)-a_i \end{aligned} \]

把 \(|i-j|\) 拆为 \(\max(i-j,j-i)\):

\[p\geq \max\left(\max_j\left(a_j+\sqrt{i-j}\right),\max_j\left(a_j+\sqrt{j-i}\right)\right)-a_i \]

两部分做法是一样的,这里只说第一部分。

如果设函数 \(f_j(x)=\sqrt{x-j}+a_j\),那么我们就是要求这些函数在每个 \(x=i\) 的最大值。

盗一张 Flash_Hu 巨佬的图:

显然一个函数至多会对应一个区间的最大值,而且对应着最大值的函数肯定越往后编号越大(因为导致最大值的函数改变的原因只可能是加入了一个编号更大的函数)。

那么我们从编号小到编号大加入这些函数并且用栈维护对应着最大值的函数。

新加入一个函数时,如果它能超过当前栈顶的函数,那么就求交。注意求得的交点也可能在栈顶的函数所对应的最大值区间的左边,这时需要弹出栈顶,然后和新的栈顶再进行比较。比如下图这种情况:

在这里插入图片描述

我们先加入了函数 \(f\) 和 \(h\),再加入函数 \(g\) 时,发现 \(g\) 与栈顶 \(h\) 的交点在 \(h\) 对应的最大值区域的左边,那么就需要弹出 \(h\),重新让 \(f\) 和 \(g\) 比较。

代码如下:

#include<bits/stdc++.h>

#define N 500010

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct data
{
	int p,l,r;
	data(){};
	data(int a,int b,int c){p=a,l=b,r=c;}
}q[N];

int n,a[N];
int maxid[N];
int tail;

double gety(int i,int x)
{
	return sqrt(abs(x-i))+1.0*a[i];
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	q[++tail]=data(1,1,n);
	for(int i=2;i<=n;i++)
	{
		if(a[i]<=a[q[tail].p]) continue;
		if(gety(i,n)>gety(q[tail].p,n))
		{
			int l=i,r=n,ans=-1;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(gety(i,mid)>gety(q[tail].p,mid)) ans=mid,r=mid-1;
				else l=mid+1;
			}
			if(ans<=q[tail].l)
			{
				tail--;
				i--;
				continue;
			}
			q[tail].r=ans-1;
			q[++tail]=data(i,ans,n);
		}
	}
	for(int i=n;i>=1;i--)
	{
		if(i<q[tail].l) tail--;
		maxid[i]=q[tail].p;
	}
	q[++tail]=data(n,1,n);
	for(int i=n-1;i>=1;i--)
	{
		if(a[i]<=a[q[tail].p]) continue;
		if(gety(i,1)>gety(q[tail].p,1))
		{
			int l=1,r=i,ans=-1;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(gety(i,mid)>gety(q[tail].p,mid)) ans=mid,l=mid+1;
				else r=mid-1;
			}
			if(ans>=q[tail].r)
			{
				tail--;
				i++;
				continue;
			}
			q[tail].l=ans+1;
			q[++tail]=data(i,1,ans);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(i>q[tail].r) tail--;
		double x=max(gety(q[tail].p,i),gety(maxid[i],i));
		printf("%d\n",max(0,(int)ceil(x-a[i])));
	}
	return 0;
}

标签:Conductor,JSOI2016,max,POI2011,mid,gety,tail,ans,函数
From: https://www.cnblogs.com/ez-lcw/p/16838355.html

相关文章

  • 【BZOJ2212】【POI2011】【XSY2014】Tree Rotation(线段树合并)
    输入格式真的毒瘤权值线段树合并。我们先对每一个叶子建一棵权值线段树,并把它自己的权值插入到里面。我们不妨设原树中当前节点为\(u\),爸爸\(fa\),左儿子\(lc\),右儿子......
  • [POI2011]Lightning Conductor
    做题时间:2022.10.14\(【题目描述】\)给定一个长度为\(n(n\leq5\times10^5)\)的非负整数序列\(a(a_i\leq10^9)\),对于\(\foralli\in[1,n]\),求出最小的非负整数\(p......
  • P3514 [POI2011]LIZ-Lollipop
    给定长度为\(n\)的序列,里面的元素为1或2,求是否有一种方案,取出连续的一段,使得到的元素和等于给定的值,若可以则输出一种方案。多组询问,\(n,q\leq10^6\)。感觉有点水,典......
  • luoguP3521 [POI2011]ROT-Tree Rotations【线段树】
    你要写热,就不能只写热。要写酷暑,写骄阳,写他人耳闻便生恐的炙烤和炎灼。要写白日出门一刻便肤色黝黑,背心透彻。写求雨心切,写出行伞遮。写夜晚不停的风扇和蝉聒。写鸡......
  • Semiconductor
    Someofthepropertiesofsemiconductormaterialswereobservedthroughoutthemid19thandfirstdecadesofthe20thcentury.Developmentsinquantumphysics......