zoukankan      html  css  js  c++  java
  • 「NOI2016」国王饮水记(猜结论+动态规划+斜率优化)

    https://loj.ac/problem/2087

    干脆把这年NOI改成猜结论大赛好了。

    先把(h)从小到大排序。

    上来先猜三个显然的结论:
    1.一个(h[i])不会被用多次
    2.我们用到的一定是(h)的一个后缀
    3.(h)的后缀用法,把(h)的后缀划分成若干段,从左往右每次合并一段

    (f[i][j])表示合并了(i)次,用了(j)以前的最大答案。

    (s)表示(h)的前缀和,则转移:
    $ f[i][j]=max(frac{f[i-1][k]-s[k]+s[i]}{i-k+1})$

    暴力就有60分了。

    考虑这个相当于二维平面上若干点,要求一个点P和这些点连线的最大斜率。

    4.看起来有决策单调性,所以可以用分治优化转移,应该有70分了。

    5.答案点一定在凸包上,对于这题,答案点一定在上凸壳,可以在上面三分(二分)。

    结合,4,5,可以得到单调队列维护凸壳的做法,复杂度:(O(nkp)),可以获得85分,用double做后面的,可以获得91分。

    接着开始非人类:
    (h)互不相同性质:
    6.前一段长度一定大于等于后一段的长度。
    7.长度大于1的区间只有(O(log frac{nh}{H})),*这个我已经感受不到正确性了。

    于是只做14次dp,剩下的一次扫一遍求最优。

    中间可以用double算来卡常数。

    Code(除掉高精度模板):

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    #define db Decimal
    
    const int N = 8005;
    
    int n, k, p;
    int h[N];
    
    db f[N], g[N], s[N];
    
    struct P {
    	int x; double y;
    	P(){}
    	P(int _x, double _y) {
    		x = _x, y = _y;
    	}
    };
    
    P operator - (P a, P b) {
    	return P(a.x - b.x, a.y - b.y);
    }
    
    db operator ^ (P a, P b) {
    	return a.x * b.y - a.y * b.x;
    }
    
    P z[N]; int L, R;
    
    void add(P a) {
    	while(L < R && ((a - z[R]) ^ (z[R] - z[R - 1])) >= 0) R --;
    	z[++ R] = a;
    }
    db qry(P a, P b) { return (b.y - a.y) / (b.x - a.x);}
    int qry(P a) {
    	while(L < R && qry(z[L + 1], a) > qry(z[L], a)) L ++;
    	return z[L].x + 1;
    }
    
    int main() {
    	freopen("a.in", "r", stdin);
    	scanf("%d %d %d", &n, &k, &p);
    	fo(i, 1, n) scanf("%d", &h[i]);
    	sort(h + 2, h + n + 1);
    	if(k >= n) {
    		db ans = db(h[1]);
    		fo(i, 2, n) {
    			if((db) h[i] > ans)
    				ans = (ans + h[i]) / 2;
    		}
    		cout << ans.to_string(p) << "
    ";
    		return 0;
    	}
    	fo(i, 2, n) s[i] = s[i - 1] + db(h[i]);
    	fo(i, 1, n) f[i] = db(h[1]);
    	fo(t, 1, min(14, k)) {
    		L = 1, R = 0;
    		fo(i, 1, n) {
    			g[i] = f[i];
    			add(P(i - 1, (s[i] - f[i]).to_double()));
    			int x = qry(P(i, s[i].to_double()));
    			f[i] = max(f[i], (g[x] + s[i] - s[x]) / (i - x + 1));
    		}
    	}
    	db ans = db(0);
    	if(k <= 14) {
    		fo(i, 2, n) ans = max(ans, f[i]);
    	} else {
    		int st = max(1, n - (k - 14));
    		ans = db(f[st]);
    		fo(i, st + 1, n) {
    			ans = (ans + h[i]) / 2;
    			ans = max(ans, f[i]);
    		}
    	}
    	cout << ans.to_string(p) << "
    ";
    }
    
  • 相关阅读:
    A1044. Shopping in Mars (25)
    A1019. General Palindromic Number (20)
    A1018. Public Bike Management (30)
    26850: 收集数码晶体 有40%错误
    A1016. Phone Bills (25)
    A1014. Waiting in Line (30)
    A1011. World Cup Betting (20)
    A1010. Radix (25)
    A1009. Product of Polynomials (25)
    A1008. Elevator (20)
  • 原文地址:https://www.cnblogs.com/coldchair/p/12803643.html
Copyright © 2011-2022 走看看