P3515 [POI2011]Lightning Conductor

首先进行一步转化

$a_j \leq a_i + q - sqrt(abs(i - j))$

$a_i + q \geq a_j + sqrt(abs(i-j))$

即 $q = max (a_j + sqrt(abs(i-j))) - a_i $

我们对$i \geq j 和 j > i$ 分类讨论, 其实解决一种情况后将序列翻转再做一遍即可

有一种O($n^2$)的dp暴力应该不难想到

那么我们现在思考如何以比较优秀的时间复杂度解决

这里涉及到决策单调性

简单的说, 对于i来说, 它的答案来源是另一点j,

那么所有答案来源排成的序列$j_1,j_2,j_3,\cdots j_n$ 具有单调性

比如: 1112255566666666678888

那么我们可以考虑对于每一个i, 它可以成为哪一段区间的答案

即一个三元组(l, r, i) 对应i控制l到r

可以二分+栈(或队列)处理

二分i和栈顶答案相等临界, 若临界小于l则弹栈重复操作

否则将新的(l, r, i) 压倒栈中

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
const int N = 500080;
struct node{
    ll l, r, x;
};
deque<node> q;
ll read() {
    ll x = 0, f = 1;
    char c = getchar();
    while (!isdigit(c)) {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (isdigit(c)) {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return x * f;
} //快读
ll n;
long double ans[N], a[N];
bool check(ll x,ll y,ll k) {
    return a[x] + sqrt(k - x) > a[y] + sqrt(k - y);
}
void work(void) {
    node k = (node){1, n, 1};
    for (ll i = 2;i <= n; i++) {
        if (a[i] < a[k.x]) continue; //剪枝, 如果满足则它一定不会有贡献
        ll l = i, r = n, mid;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (check(k.x, i, mid)) l = mid + 1;
            else r = mid - 1;
        }//二分
        if (l == n + 1) continue;
        if (l <= k.l) {
            k = q.front();
            q.pop_front();
            i--;
            continue;
        }//弹栈
        k.r = r;
        q.push_front(k);
        k = (node){l, n, i}; //压栈
    }
    q.push_front(k);
    k = q.back();
    q.pop_back();
    for (ll i = 1;i <= n; i++) {
        if (k.r < i) {
            k = q.back();
            q.pop_back();
        }
        ans[i] = max(ans[i], a[k.x] + sqrt(i - k.x)); //要做两次,所以取max
    }
}

int main() {
    n = read();
    for (int i = 1;i <= n; i++)
        a[i] = read(), ans[i] = a[i];
    work();
    for (int j = 1;j << 1 <= n; j++)
    swap(a[j], a[n-j+1]), swap(ans[j], ans[n-j+1]);
    //翻转
    while (q.size()) q.pop_front();
    work();
    ///*
    for (int i = n;i >= 1; i--)
        printf ("%d\n", int(ceil(ans[i]) - a[i]));
        //*/
    return 0;
}

原文地址:https://www.cnblogs.com/Hs-black/p/11626103.html

时间: 2024-08-27 17:56:16

P3515 [POI2011]Lightning Conductor的相关文章

P3515 [POI2011]Lightning Conductor(决策单调性分治)

P3515 [POI2011]Lightning Conductor 式子可转化为:$p>=a_j-a_i+sqrt(i-j) (j<i)$ $j>i$的情况,把上式翻转即可得到 下面给一张图证明这是满足决策单调性的 把$a_j+sqrt(i-j)$表示在坐标系上 显然$sqrt(i-j)$的增长速度趋缓 曲线$a$被曲线$b$超过后是无法翻身的 对两个方向进行决策单调性分治,取$max$即可 #include<iostream> #include<cstdio>

P3515 [POI2011]Lightning Conductor[决策单调性优化]

给定一序列,求对于每一个$a_i$的最小非负整数$p_i$,使得$\forall j \neq i $有$ p_i>=a_j-a_i+ \sqrt{|i-j|}$. 绝对值很烦 ,先分左右情况单独做.现在假设j都在i左边,则$p_i=max{a_j-a_i+ \sqrt{i-j}}=max{a_j+ \sqrt{i-j} }-a_i$.带根号,不易斜率优化,考虑证决策单调性. 假设最优决策为j,j之前的任意决策称之为$j'$,则有 $f[j]+\sqrt{i-j} \geqslant f[j']

【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 I

BZOJ2216 : [Poi2011]Lightning Conductor

$f[i]=\max(a[j]+\lceil\sqrt{|i-j|}\rceil)$, 拆开绝对值,考虑j<i,则决策具有单调性,j>i同理, 所以可以用分治$O(nlogn)$解决. #include<cstdio> #include<cmath> #define N 500010 int n,i,l,r,mid,a[N],b[N],f[N],g[N]; inline void read(int&a){char c;while(!(((c=getchar())

bzoj2216: [Poi2011]Lightning Conductor(分治决策单调性优化)

每个pi要求 这个只需要正反DP(?)一次就行了,可以发现这个是有决策单调性的,用分治优化 #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int maxn=500010,inf=1e9; int n; int a[

【bzoj2216】[Poi2011]Lightning Conductor 1D1D动态规划优化

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 6532424 Sample Output 235354 题解 http

[POI2011]Lightning Conductor

题面在这里 description 已知一个长度为\(n\)的序列\(a_1,a_2,...,a_n\). 对于每个\(1\le i\le n\),找到最小的非负整数\(p\), 满足对于任意的\(1\le j\le n\),\(a_j\le a_i+p-\sqrt{|i-j|}\) data range \[n\le 5\times 10^5,a_i\le 10^9\] solution 绝对值怎么办? 我们先从左到右\(DP\ j< i\)的部分(此时有\(|i-j|=i-j\)), 再右到

@bzoj - [email&#160;protected] [Poi2011]Lightning Conductor

目录 @[email protected] @[email protected] @part - [email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @version - [email protected] @version - [email protected] @[email protected] @[email protected] 已知一个长度为

BZOJ 2216 Lightning Conductor

决策单调.整体二分. #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define maxn 500500 using namespace std; int n,a[maxn],f[maxn],g[maxn]; void dp1(int left,int right,int l,int r) { if (left&