zoukankan      html  css  js  c++  java
  • [题解/模板]luogu_P3515_LightningConductor(决策单调性

    已知一个长度为n的序列a1,a2,...,an。

    对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))

    每个点的$p=max(a[j]-a[i]+sqrt{|i-j|}$,可以想到dp,$f[i]=max(a[j]-a[i]+sqrt{|i-j|}$

    绝对值比较常见的做法可以分类讨论去掉,比如我们只处理$j<i$的情况,然后在倒着做一遍就可以了

    对于这个根号,整理一下式子啥的好像并不能用斜率优化之类的,不妨考虑决策单调性,

    证明:

    需证:对于两个决策点$p1,p2$和$i1<i2$,若从$p2$转移到$i1$比从$p1$转移到$i1$优,则从$p2$转移到$i2$也比$p1$优

    所以已知$a[p1]-a[i1]+sqrt{p1-i1}<a[p2]-a[i1]+sqrt{p2-i1}$,求证$a[p1]-a[i2]+sqrt{p1-i2}<a[p2]-a[i2]+sqrt{p2-i2}$

    发现两个式子化简后只有根号里有$i1,i2$,所以可以从根号下手,注意$i1<i2$,也就是说$p-i1>p-i2$,相当于根号这个函数的自变量变小了一点,并且两边变小的值相同

    那么就可以想到关于斜率/导数之类的东西,也就是根号函数斜率递减,在前面和后面自变量变化相同的值,函数值变化有一个大小关系:对于$i<j,sqrt{i-Delta}-sqrt{i}>sqrt{j-Delta}-sqrt{j}$,变化量相同时自变量小的函数值变化量大,那么单调性就显然了

    并没写分治做法

    二分栈流程:

    1.排除队头所有右端点小于$i$的元素,然后把队头元素左端点设为$i$

    2.用队头更新$f[i]$

    3.排除所有队尾比$i$不优秀的决策

    4.若队列空则直接插入$i$,否则:

      二分找到转折点$pos$,若$pos$不与队尾左端点重合,修改队尾元素右端点为$pos-1$,否则弹出队尾

      若$pos<=n$插入$i$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int maxn=500009;
    int n,a[maxn];
    double f[maxn],g[maxn],sq[maxn];
    struct node{
        int p,l,r;
    }q[maxn];
    double calc(int j,int i){
        return a[j]+sq[i-j];
    }
    int bound(int t,int i){
        int pos=q[t].r+1,l=q[t].l,r=q[t].r;
        while(l<=r){
            int mid=l+r>>1;
            if(calc(q[t].p,mid)<calc(i,mid))pos=mid,r=mid-1;
            else l=mid+1;
        }
        return pos;
    }
    void work(){
        int head=1,tail=0,pos;
        for(int i=1;i<=n;i++){
            while(head<=tail && q[head].r<i)head++;q[head].l=i;
            f[i]=max(f[i],calc(q[head].p,i)-a[i]);
            while(head<=tail && calc(q[tail].p,q[tail].l)<calc(i,q[tail].l))tail--;
            if(head>tail)q[++tail]=(node){i,i,n};
            else{
                int pos=bound(tail,i);
                if(pos!=q[tail].l)q[tail].r=pos-1;
                else tail--;
                if(pos<=n)q[++tail]=(node){i,pos,n};
            }
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),sq[i]=sqrt(i);
        work();
        for(int i=1,j=n;i<j;i++,j--)
        swap(a[i],a[j]),swap(f[i],f[j]);
        work();
        for(int i=n;i>=1;i--)
        printf("%d
    ",(int)(ceil(f[i])));
        
    }
  • 相关阅读:
    C# 中使用反射的优缺点
    winfrom---Window 消息大全
    Entity Framework:三种开发模式实现数据访问
    asp.net Core 2.0 MVC为Controller或Action添加定制特性实现登录验证
    [十二省联考2019] 异或粽子 解题报告 (可持久化Trie+堆)
    [jzoj 3175] 数树数 解题报告 (树链剖分)
    [jzoj 5661] 药香沁鼻 解题报告 (DP+dfs序)
    [jzoj 5662] 尺树寸泓 解题报告 (线段树+中序遍历)
    [jzoj 5664] [GDOI2018Day1模拟4.6] 凫趋雀跃 解题报告(容斥原理)
    范德蒙恒等式学习笔记
  • 原文地址:https://www.cnblogs.com/superminivan/p/11489572.html
Copyright © 2011-2022 走看看