选址 [差分]

选址


\color{red}{正解部分}

考虑什么时候 ii 会对 xx 产生贡献,
cixi2>0c_i-|x-i|^2 > 0 时, 会产生贡献, 解方程得到 x(ici,i+ci)x∈(i-\sqrt{c_i}, i+\sqrt{c_i}) .

\thereforex(ici,i+ci)x∈(i-\sqrt{c_i}, i+\sqrt{c_i}) 时, ii 会对 xx 产生贡献 .

贡献为 cii2+2ixx2c_i-i^2 + 2ix - x^2,

  • cii2c_i-i^2 为常数, 可以直接使用一个差分数组处理 .
  • 2ix2i*x 的系数 2i2i 使用一个差分数组处理 .
  • 1x21*x^2 的系数 11 使用一个差分数组处理 .

\color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register
typedef long long ll;

const int maxn = 100005;

int N;

ll C[maxn];
ll cf1[maxn];
ll cf2[maxn];
ll cf3[maxn];

int main(){
        scanf("%d", &N);
        for(reg int i = 1; i <= N; i ++) scanf("%lld", &C[i]);
        for(reg int i = 1; i <= N; i ++){
                int l = std::max(1, (int)(i*1.0-sqrt(C[i])+1.0));
                int r = std::min(N, (int)(i*1.0+sqrt(C[i])));
                cf1[l] += C[i] - 1ll*i*i,
                cf1[r+1] -= C[i] - 1ll*i*i;
                cf2[l] += 2ll*i, cf2[r+1] -= 2ll*i;
                cf3[l] ++, cf3[r+1] --;
        }
        ll a = 0, b = 0, c = 0;
        for(reg int i = 1; i <= N; i ++){
                a += cf1[i], b += cf2[i], c += cf3[i];
                printf("%lld ", a + b*i - c*i*i);
        }
        return 0;
}
posted @ 2019-08-20 20:21  XXX_Zbr  阅读(126)  评论(0编辑  收藏  举报