• BZOJ2216: [Poi2011]Lightning Conductor


    第一道此类的题,所以这是一篇假的博客,定理不会证明不理性

    也不一定对

    我是从这篇博客看的 = = 

    很显然是让你求 p[i] = max{a[j] + sqrt(i - j)} - a[i]

    就是 max{a[j] + sqrt(|i - j|)}

    这是一个 1D/1D 动态规划

    考虑对于绝对值的情况不好做,那就强行去掉绝对值
    之后正反各做一遍

    设 sqrt(i - j) 为 w[j, i]

    它显然满足区间包含单调性,考虑证明它满足四边形不等式

    设 j < j + 1 < i < i + 1

    应该是 w[j, i] + w[j + 1, i + 1] 与 w[j + 1, i] + w[j, i + 1] 的关系

    由于函数 y = sqrt(x) 的图像是斜率递减的

    所以显然有 w[j, i] + w[j + 1, i + 1] > w[j + 1, i] + w[j, i + 1] ①

    考虑决策单调性,设对 i 有 a[j + 1] + w[j + 1, i] > a[j] + w[j, i] ②

    ① + ② 得 a[j + 1] + w[j + 1, i + 1] > a[j] + w[j, i + 1]

    所以若对 i 成立对 i + 1 也成立

    所以决策点是单调的

    那么整个序列每个位置对应的最优决策点组成的序列应该是这样:

    111133336666....

    可以用队列来维护它,队列中存三元组 (l, r, id) 
    表示 id 这个决策点能更新的区间为 [l, r]

    实际操作起来是这样的:

    考虑当前点 i 的影响,若它能比之前的一些点优,
    它一定是将整个序列从某一个位置开始到 n 的最优决策点

    那么它能比之前点优的条件就是对于 n ,当前点比队尾优

    然后会有一些决策点被当前点废掉,
    条件就是对于一个决策点 p , 若在它能更新的区间左端点 l 处, i 比 p 优,
    则这个点没有用了

    那么若队列未被弹空,最后剩下的队尾一定是满足在它的 l 处 它比 i 优

    r 就不一定了,这里在队尾的 [l, r] 中二分第一个 i 比 id 优的位置,设为 dst

    那么队尾的 r 就要改成 dst - 1

    并将 i 入队,区间为 [dst, n]


    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    const int MAXN = 500005;
    
    struct INFO{
    	int l, r, id;
    	INFO(int L = 0, int R = 0, int ID = 0) {l = L; r = R; id = ID;}
    }q[MAXN];
    int n, hd, tl;
    int a[MAXN], b[MAXN];
    double f1[MAXN], f2[MAXN];
    
    inline int rd() {
    	register int x = 0;
    	register char c = getchar();
    	while(!isdigit(c)) c = getchar();
    	while(isdigit(c)) {
    		x = x * 10 + (c ^ 48);
    		c = getchar();
    	}
    	return x;
    }
    inline int hfs(int l, int r, int bck, int cur, int *arr) {
    	register int mid = 0, ans = l;
    	while(l <= r) {
    		mid = ((l + r) >> 1);
    		if((double)arr[bck] + sqrt(mid - bck) < (double)arr[cur] + sqrt(mid - cur)) {
    			ans = mid;
    			r = mid - 1;
    		} else l = mid + 1;
    	}
    	return l;
    }
    inline void work(int *val, double *f) {
    	hd = 1; tl = 0;
    	q[++tl] = INFO(1, n, 1);
    	for(int i = 2; i <= n; ++i) {
    		++q[hd].l;
    		//printf("i = %d, hd = %d, tl = %d
    ", i, hd, tl);
    		while(hd <= tl && q[hd].r < q[hd].l) ++hd;
    		if((tl < hd) || ((double)val[i] + sqrt(n - i) > (double)val[q[tl].id] + sqrt(n - q[tl].id))) {
    			while(hd <= tl && ((double)val[i] + sqrt(q[tl].l - i) > (double)val[q[tl].id] + sqrt(q[tl].l - q[tl].id))) --tl;
    			if(tl < hd) {
    				q[++tl] = INFO(i, n, i);
    			} else {
    				register int dst = hfs(q[tl].l, q[tl].r, q[tl].id, i, val);
    				q[tl].r = dst - 1;
    				q[++tl] = INFO(dst, n, i);
    			}
    		}
    		f[i] = (double)val[q[hd].id] + sqrt(i - q[hd].id) - val[i];
    	}
    	return;
    }
    
    int main() {
    	n = rd();
    	for(int i = 1; i <= n; ++i) 
    		a[i] = b[n - i + 1] = rd();
    	work(a, f1);
    	work(b, f2);
    	for(int i = 1; i <= n; ++i) 
    		printf("%d
    ", max(0, (int)ceil(max(f1[i], f2[n - i + 1]))));
    	return 0;
    }
  • 相关阅读:
    查看Ubuntu版本
    CentOS下实现postgresql开机自启动
    CentOS下查看crontab执行历史记录
    经常使用的一个python logging封装,支持同时向console和文件输出
    crontab中执行postgresql命令
    postgresql下一种对已有数据进行重新分表的plpgsql脚本
    2012需要分析的一些技术(1)
    Python Extension Packages for Windows
    一个简单的根据行数对大文件进行分片的python程序
    偶拾
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9770718.html
Copyright © 2020-2023  润新知