zoukankan      html  css  js  c++  java
  • SCOI2014 方伯伯的玉米田

    题目传送门

    我可以说方伯伯浪费粮食么……


    首先要知道一个结论:

    每次操作的右端点一定是(n)

    因为如果拔高一段区间,区间内部的玉米的相对高度不会发生变化,区间左边的点贡献增加(x),但区间右边的点贡献会减少。如果我们将这段拔高区间的右端点挪到(n)上,区间左边的点贡献还是会增加(x),区间右边不存在点,也就是贡献不会减少。所以当左端点固定时,右端点是(n)能保证最优

    然后我们就可以比较容易的写出一个状态转移方程:
    f[i][k]表示以i为结尾,用了k次拔高操作后的最长不下降子序列的长度
    f[i][k] = max { f[j][l] } + 1 (0 < j < i, 0 <= l <= k, h[i] + k >= h[j] + l)

    暴力转移是(O(nk))的。对于f[i][k]我们显然要求一个二维前缀最大值,可以用二维树状数组来优化,这样就可以优化成(O(log{n}log{k})),总时间复杂度为(O(nklog{n}log{k}))

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    #define lb(__a) (__a & (-__a))
    using namespace std;
    LL read() {
    	LL k = 0, f = 1; char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		k = k * 10 + c - 48, c = getchar();
    	return k * f;
    }
    int n, k, tree[20010][510], maxn;
    int Maxn(int x, int y) {
    	int anss = 0;
    	for(int i = x; i; i -= lb(i))
    		for(int j = y; j; j -= lb(j))
    			anss = max(anss, tree[i][j]);
    	return anss;
    }
    void update(int x, int y, int val) {
    	for(int i = x; i <= maxn + k; i += lb(i))
    		for(int j = y; j <= k+1; j += lb(j))
    			tree[i][j] = max(tree[i][j], val);
    }
    int h[10010], ans;
    int main() {
    	n = read(), k = read();
    	for(int i = 1; i <= n; ++i)
    		h[i] = read(), maxn = max(h[i], maxn);
    	for(int i = 1; i <= n; ++i)
    		for(int j = k; j >= 0; --j) {
    			int x = Maxn(h[i]+j, j+1) + 1;
    			ans = max(ans, x);
    			update(h[i]+j, j+1, x);
    		}
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    C#微信开发
    3-4:字符串方法
    2-4-1 元组
    2-3-3 列表方法
    2-2-3:序列(字符串)乘法(p32)
    3-3字符串格式化(p47)
    2-2:分片
    2-1:Print date(p28)
    old.2.三次登录机会
    old.2.sum(1-2+3-4+...+99)
  • 原文地址:https://www.cnblogs.com/morslin/p/11855795.html
Copyright © 2011-2022 走看看