zoukankan      html  css  js  c++  java
  • 【BZOJ2216】[Poi2011]Lightning Conductor 决策单调性

    【BZOJ2216】[Poi2011]Lightning Conductor

    Description

    已知一个长度为n的序列a1,a2,...,an。
    对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))

    Input

    第一行n,(1<=n<=500000)
    下面每行一个整数,其中第i行是ai。(0<=ai<=1000000000)

    Output

    n行,第i行表示对于i,得到的p

    Sample Input

    6
    5
    3
    2
    4
    2
    4

    Sample Output

    2
    3
    5
    3
    5
    4

    题解:决策单调性不只是斜率优化~

    p>=aj-ai+sqrt(abs(i-j)),有绝对值怎么办?拆开讨论两边就行。

    你会发现,sqrt函数的增长是越来越慢的,也就意味着如果存在i<j<k,且对于k来说j比i更优,那么之后的i再也不会比j优了。我们想找到的,就是当前节点最远能更新到哪个点。

    不难发现,每个点能做出贡献的区间是一段连续的区间(可能为空)。我们可以用双向队列来找出每个点能作用的区间的左右端点lp和rp,具体方法:

    1.枚举到当前点i时,先更新i的答案,然后将队首的lp改为i,如果队首lp>rp,则弹出队首。
    2.如果队列不为空,且i对于n不如队尾优,说明i永远干不掉队尾,则不将i加入队列。
    否则,如果i对于lp[队尾]比队尾更优,则弹出队尾。最后,i干掉队尾的位置就落在lp[队尾]和rp[队尾]之间,二分一下即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int maxn=500010;
    int n,h,t;
    int lp[maxn],rp[maxn],v[maxn],p[maxn],q[maxn];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    double solve(int a,int b)
    {
    	return v[a]-v[b]+sqrt(abs(b-a));
    }
    int main()
    {
    	n=rd();
    	int i,l,r,mid;
    	for(i=1;i<=n;i++)	v[i]=rd();
    	for(h=1,t=0,i=1;i<=n;i++)
    	{
    		while(h<=t&&rp[q[h]]<i)	h++;
    		if(h<=t)	lp[q[h]]=i,p[i]=max(p[i],(int)ceil(solve(q[h],i)));
    		if(h>t||solve(i,n)>solve(q[t],n))
    		{
    			rp[i]=n;
    			while(h<=t&&solve(i,lp[q[t]])>=solve(q[t],lp[q[t]]))	t--;
    			if(h<=t)
    			{
    				l=lp[q[t]],r=rp[q[t]]+1;
    				while(l<r)
    				{
    					mid=l+r>>1;
    					if(solve(i,mid)<solve(q[t],mid))	l=mid+1;
    					else	r=mid;
    				}
    				rp[q[t]]=l-1,lp[i]=l;
    			}
    			else	lp[i]=i+1;
    			q[++t]=i;
    		}
    	}
    	for(h=1,t=0,i=n;i>=1;i--)
    	{
    		while(h<=t&&lp[q[h]]>i)	h++;
    		if(h<=t)	rp[q[h]]=i,p[i]=max(p[i],(int)ceil(solve(q[h],i)));
    		if(h>t||solve(i,1)>solve(q[t],1))
    		{
    			lp[i]=1;
    			while(h<=t&&solve(i,rp[q[t]])>=solve(q[t],rp[q[t]]))	t--;
    			if(h<=t)
    			{
    				l=lp[q[t]],r=rp[q[t]];
    				while(l<r)
    				{
    					mid=l+r>>1;
    					if(solve(i,mid)<solve(q[t],mid))	r=mid;
    					else	l=mid+1;
    				}
    				lp[q[t]]=r,rp[i]=r-1;
    			}
    			else	rp[i]=i-1;
    			q[++t]=i;
    		}
    	}
    	for(i=1;i<=n;i++)	printf("%d
    ",p[i]);
    	return 0;
    }
  • 相关阅读:
    枚举
    枚举
    比特币中的密码学原理
    贪心
    dp
    二分
    mac解决matplotlib中文乱码
    Keras使用多个GPU并行
    pyspark使用-dataframe操作
    箱线图
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7258256.html
Copyright © 2011-2022 走看看