首页 > 其他 > 详细

JZYZOJ 1326 超级教主

时间:2019-10-18 17:40:02      阅读:56      评论:0      收藏:0      [点我收藏+]

技术分享图片

技术分享图片


题解

首先向考虑小范围的数据。

\(a[i]\)表示前\(i\)个球的总能量,一个前缀和很好理解的

\(f[i]\)表示获得第\(i\)个球后的总能量

呢么很显然我们可以\(DP\)了!!

f[i] = max(f[j] + a[i]-a[j] - 100*i)

呢么这就是一个\(O(n^2)\)的算法。很显然过不了。别给我说\(n^2\)过百万

呢么自然而然就是优化

常见的优化就是压维。呵呵,我不会

好吧,单调性优化

我们发现查找\(j\)是很费时的,我们可不可以用\(O(1)\)的办法把\(j\)找出来呢???

首先我们用一个队列来储存\(j\)的最优值,每次取队头就好了

呢么我们怎么更新队列呢

队头简单如果\(f[j]\)的能量小于当前\(i\)的高度更新掉就好了

队尾比较难理解先看代码

while(f[i] - a[i] > f[q[r]] - a[q[r]]) r--;

\(f[i] - a[i]\) 就是已经获得\(i\)的能量后,损失能量的总和的相反数

很自然\(i\)损失的能量小于\(q[r]\)的能量肯定要舍弃队尾

因为是相反数,所以要变成大于(不等式的性质,不等式两侧同乘一个负数,不等式要变号)


coding

#include <bits/stdc++.h>
using namespace std;


const int N = 2000005;
int n,f[N] = {},a[N] = {};
int cnt,ans = 0,q[N] = {},l = 0,r = 1;


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


int main()
{
    n = read(); f[0] = read();
    for(register int i = 1;i <= n;i++) a[i] = a[i-1] + read();
    
    for(register int i = 1;i <= n;i++)
    {
        while(f[q[l]] < 100*i && l < r) l++;
        f[i] = f[q[l]] + a[i]-a[q[l]] - 100*i;
        while(f[i] - a[i] > f[q[r]] - a[q[r]]) r--;
        q[++r] = i;
    }
    
    printf("%d\n",f[n]);
    return 0;
}

JZYZOJ 1326 超级教主

原文:https://www.cnblogs.com/Mark-X/p/11699568.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!