• [BZOJ2216|Luogu P3515] [Poi2011]Lightning Conductor (线性解法)


    [BZOJ2216|Luogu P3515] [Poi2011]Lightning Conductor (线性解法)

    老题了

    问题描述:

    给定(a_i),求(f_i=max_j{a_j-a_i+sqrt{|i-j|}})

    首先可以分(j<i)(j>i)两种情况考虑,下面只考虑(j<i)的情况

    (g_i(x)=sqrt{x-i}+a_i),比较(g_i(x),g_j(x)(i<j))([j,infty))上的大小关系时时,有几种情况

    1. (g_i(x))恒大于(g_j(x)),即(a_ige a_j)

    2. (delta(x)=g_i(x)-g_j(x)),则(displaystyle delta'(x)=frac{1}{2sqrt{x-i}}-frac{1}{2sqrt{x-j}}<0)

      1. (delta(0)leq 0),则(g_i(x))恒小于(g_j(x))
      2. 求得(delta(x))的零点,在零点左侧(g_i(x))大,右侧(g_j(x))

    容易发现这样函数之间的关系类似直线之间的关系,都是在某一界点处大小关系改变

    因此可以像维护直线凸包一样维护(g_i(x))的凸包,再根据查询的单调性完成线性查询

    维护凸包时需要求(g_i(x),g_j(x)(i<j))的交点,这个方程大概可以归纳为

    [sqrt{x+d}-sqrt{x}=c ]

    自然可以在整数域上二分求解这个方程的近似根,但是实际上可以用一点点数学手段(O(1))求解准确根

    (t=sqrt x),原方程变为(sqrt {y^2+d}-y=c)

    (y^2+d=y^2+c^2+2cyLongrightarrow y=frac{d-c^2}{2c})

    (displaystyle x=(frac{d-c^2}{2c})^2)

    计算常数略大,我写得也不是很好,所以不算太快

    Luogu Submission

    char buf[200000],*p1,*p2;
    #define getchar() (((p1==p2)&&(p2=(p1=buf)+fread(buf,1,200000,stdin))),*p1++)
    int rd(){
    	int s=0; static char c;
    	while(c=getchar(),c<48);
    	do s=(s<<1)+(s<<3)+c-48;
    	while(c=getchar(),c>47);
    	return s;
    }
    
    const int N=5e5+10,INF=1e9+10;
    
    int n;
    int a[N],f[N],_sqrt[N];
    int Q[N],L,R;
    
    db Cross(int i,int j){
    	int d=j-i,c=a[j]-a[i];
    	if(1ll*c*c>=d) return -1e90;
    	db t=(d-1ll*c*c)/(2.*c);
    	return t*t+j;
    }
    int Get(int i,int j){ return _sqrt[j-i]+a[i]-a[j]; }
    void Solve(){
    	L=1,R=0;
    	rep(i,1,n) {
    		while(L<R && i>=Cross(Q[L],Q[L+1])) L++;
    		if(L<=R) cmax(f[i],Get(Q[L],i));
    		if(L<=R && a[Q[R]]>=a[i]) continue;
    		while(L<R && Cross(Q[R-1],Q[R])>=Cross(Q[R],i)) R--;
    		Q[++R]=i;
    	}
    }
    
    void wt(int x){
    	if(!x) return (void)putchar('0');
    	static char buf[20];
    	int l=0;
    	while(x) buf[++l]=x%10+'0',x/=10;
    	while(l) putchar(buf[l--]);
    }
    
    int main(){
    	n=rd();
    	for(int i=1,t=1;i<=n;++i) _sqrt[i]=t+=i>t*t;
    	rep(i,1,n) a[i]=rd();
    	Solve();
    	reverse(a+1,a+n+1),reverse(f+1,f+n+1);
    	Solve();
    	drep(i,n,1) wt(f[i]),putchar('
    ');
    }
    
  • 相关阅读:
    基于Mybatis3.0.6的基本操作介绍
    正则验证邮箱格式是不是正确
    Linux_文件权限
    飘逸的python
    通过Fsharp探索Enterprise Library Exception
    Oracle学习——扫盲篇
    代码块练习题:看代码写程序的执行结果。
    代码块:在Java中用{}括起来的代码
    Java中如何使用帮助文档(API)
    Java如何制作帮助文档(API)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/15371196.html
Copyright © 2020-2023  润新知