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

    题意

    给你 (n) 个数,(k) 次操作,每次可以选则一段区间全部加一,最后问最长上升子序列最长可以是多长。

    Analysis

    考虑每次加的区间,若是中间的一段,则把后面一段一起加一肯定不会更劣,所以每次修改必然是一个后缀。

    然后可以得到一个动态规划的算法:设子状态为 (dp_{i,j}) 代表到第 (i) 个位置,总共操作了 (j) 次。

    (dp_{i,j}=max(dp_{p,q}+1)) 其中 (a_p+qle a_i+j,jle q)

    一个二维的最长上升子序列问题,我们可以用二维树状数组优化到 (O(nklog{v}log{k}))

    注意树状数组从 (1) 开始而我们的 (j) 是可以为 (0) 的,所以每次要加一,另外为了保证第一维(这其实是个三维偏序),我们第二层循环(j)要从大到小。

    #include <bits/stdc++.h>
    using namespace std;
    int n, k;
    int a[10010];
    int dp[10010][510], f[10010][510];
    int ans;
    void cmax(int &x, int y) {
    	x = max(x, y);
    }
    int lowbit(int x) {
    	return x & (-x);
    }
    void change(int x, int y, int cur) {
    	for (int i = x; i <= 10000; i += lowbit(i)) {
    		for (int j = y; j <= k + 1; j += lowbit(j)) {
    			cmax(dp[i][j], cur);
    		}
    	}
    }
    int ask(int x, int y) {
    	int ret = 0;
    	for (int i = x; i; i -= lowbit(i)) {
    		for (int j = y; j; j -= lowbit(j)) {
    			cmax(ret, dp[i][j]);
    		}
    	}
    	return ret;
    }
    int main() {
    	scanf("%d%d", &n, &k);
    	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    	for (int i = 1; i <= n; i++) {
    		for (int j = k; j >= 0; j--) {
    			f[i][j] = ask(a[i] + j, j + 1) + 1;
    			change(a[i] + j, j + 1, f[i][j]);
    			ans = max(ans, f[i][j]);
    		}
    	}
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    Django框架
    Django框架
    Django框架
    Django框架
    Bootstrap框架
    前端之jQuery
    前端之BOM和DOM
    Flask框架配置管理
    lement-ui、接口、restful规范、drf、跨域问题
    Vue项目入口与小知识总结
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13670156.html
Copyright © 2011-2022 走看看