zoukankan      html  css  js  c++  java
  • bzoj 2216 Lightning Conductor

    题目传送门

      需要root权限的传送门

    题目大意

      给定一个长度为$n$的数组,要求对每个$1 leqslant i leqslant n$找到最小整数的$p$,对于任意$j$满足使得$a_{i} + p - sqrt{left | i - j ight |} geqslant a_{j}$。

      一来想到函数$y = left lceil sqrt{x} ight ceil$,至多有根号个取值,然后发现$O(nsqrt{n})$会稳T。

      对于函数$y = sqrt{x}$有一些很优美的性质,比如它的增长率不断递减(因为它的导数$y' = frac{1}{sqrt{x}}$,$y'$随$x$减小而减小)。

      所以对于两个决策点$i, j$,若满足$i < j$,如果它们在转移到$p_{k}$的时候$i$没有$j$优,那么$i$不会比$j$优了。

      同样的,如果$i$还是比$j$优,那么在$k$之前还是这样的。  

      因此决策点是单调的。

      所以我们可以用整体二分的写法。

      每次考虑$f[mid]$的函数值,找到它的最优决策点$pos$,那么可以确定左区间的决策点的范围,对于右区间同理。

    Code

     1 /**
     2  * bzoj
     3  * Problem#2216
     4  * Accepted
     5  * Time: 4516ms
     6  * Memory: 13032k
     7  */
     8 #include <bits/stdc++.h>
     9 using namespace std;
    10 typedef bool boolean;
    11 
    12 int n;
    13 int *csqr;
    14 int *ar;
    15 int *f, *g; 
    16 
    17 inline void init() {
    18     scanf("%d", &n);
    19     csqr = new int[(n + 1)];
    20     ar = new int[(n + 1)];
    21     f = new int[(n + 1)];
    22     g = new int[(n + 1)];
    23     for (int i = 1; i <= n; i++)
    24         scanf("%d", ar + i);
    25 }
    26 
    27 double *sqs;
    28 void prepare() {
    29     sqs = new double[(n + 1)];
    30     sqs[0] = 0;
    31     for (int i = 1; i <= n; i++)
    32         sqs[i] = sqrt(i);
    33 }
    34 
    35 void dividing(int* f, int l, int r, int ql, int qr) {
    36     if (l > r)    return;
    37     int mid = (l + r) >> 1, pos;
    38     double mx = 0.0, cmp;
    39     for (int i = ql; i <= qr && i <= mid; i++)
    40         if ((cmp = ar[i] + sqs[mid - i]) > mx)
    41             mx = cmp, pos = i;
    42     f[mid] = ceil(mx - ar[mid]);
    43     dividing(f, l, mid - 1, ql, pos);
    44     dividing(f, mid + 1, r, pos, qr);
    45 }
    46 
    47 inline void solve() {
    48     dividing(f, 1, n, 1, n);
    49     reverse(ar + 1, ar + n + 1);
    50     dividing(g, 1, n, 1, n);
    51     for (int i = 1; i <= n; i++)
    52         printf("%d
    ", max(f[i], g[n - i + 1])); 
    53 }
    54 
    55 int main() {
    56     init();
    57     prepare();
    58     solve();
    59     return 0;
    60 }
  • 相关阅读:
    Python异常处理
    python抽象类
    python传参*和**的区别
    python 多重继承构造函数调用顺序
    linux 自启动 | 三种方式自启动
    Linux 项目 shell 自动获取报告本机IP (1) | 通过shell 自动获取报告本机IP
    Go 基础学习笔记 (5)| 数据类型说明与使用
    GO 基础学习笔记(4)| 参数传递
    生活问题 | 对华为畅玩手机5X进行升级
    markdown 语法
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8529892.html
Copyright © 2011-2022 走看看