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;
    }
    
  • 相关阅读:
    HDU 4069 Squiggly Sudoku
    SPOJ 1771 Yet Another NQueen Problem
    POJ 3469 Dual Core CPU
    CF 118E Bertown roads
    URAL 1664 Pipeline Transportation
    POJ 3076 Sudoku
    UVA 10330 Power Transmission
    HDU 1426 Sudoku Killer
    POJ 3074 Sudoku
    HDU 3315 My Brute
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13670156.html
Copyright © 2011-2022 走看看