zoukankan      html  css  js  c++  java
  • 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
    ", int(ceil(ans[i]) - a[i]));
    		//*/
    	return 0;
    }
    
  • 相关阅读:
    ubuntu LAMP的安装
    windows中安装liunx虚拟机
    jQuery Responsive OneByOne Slider Plugin
    轮播图收集
    移动端图片延迟加载插件
    图片幻灯插件
    小tip: base64:URL背景图片与web页面性能优化
    基于HTML5的可预览多图片Ajax上传
    字体平滑解决方案
    webstorm scss编译css配置
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11626103.html
Copyright © 2011-2022 走看看