[SCOI2014]方伯伯的玉米田
阿新 • • 發佈:2018-10-15
getchar() names vma 每次 change chan namespace vmax 輸出
題目描述
方伯伯在自己的農田邊散步,他突然發現田裏的一排玉米非常的不美。這排玉米一共有N株,它們的高度參差不齊。方伯伯認為單調不下降序列很美,所以他決定先把一些玉米拔高,再把破壞美感的玉米拔除掉,使得剩下的玉米的高度構成一個單調不下降序列。方伯伯可以選擇一個區間,把這個區間的玉米全部拔高1單位高度,他可以進行最多K次這樣的操作。拔玉米則可以隨意選擇一個集合的玉米拔掉。問能最多剩多少株玉米,來構成一排美麗的玉米。
輸入輸出格式
輸入格式:
第1行包含2個整數n,K,分別表示這排玉米的數目以及最多可進行多少次操作。第2行包含n個整數,第i個數表示這排玉米,從左到右第i株玉米的高度ai。
輸出格式:
輸出1個整數,最多剩下的玉米數。
輸入輸出樣例
輸入樣例#1
3 1
2 1 3
輸出樣例#1
3
說明
1 < N < 10000,1 < K <= 500,1 <= ai <=5000
題解
首先分析題目可以得到一個性質
每次選擇的區間一定是原序列的一個後綴
這樣就可以DP了
f[i][j]表示前i個數操作j次的最長不降子序列
\(f[i][j] = f[k][j - (val[k]-val[i] > 0 ? val[k]-val[i] : 0)] + 1\)
然後考慮怎麽優化
我們發現這個轉移類似於二維數點
每次轉移是取一個一維是權值,一維是操作次數的矩形的前綴取max
所以可以用二維樹狀數組求前綴max將復雜度優化到\(nmlog^2\)
保證一維是位置,一維是權值即可
每次查詢就是要找到val[j]使小於等於 \(val[i] + k\) 且 \(k >= j\)
代碼
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int M = 6005 ; const int N = 505 ; using namespace std ; inline int read() { char c = getchar() ; int x = 0 , w = 1 ; while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; } while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; } return x*w ; } int n , m ; int val[M << 1] , Ans ; int tmax[M][N] , vmax ; inline int lowbit(int x) { return x & (-x) ; } inline void change(int v , int k , int x) { for( v ; v <= vmax + m ; v += lowbit(v)) for(int i = k ; i <= m + 1 ; i += lowbit(i)) tmax[v][i] = max(tmax[v][i] , x) ; } inline int query(int v , int k) { int temp = 0 ; for( ; v ; v -= lowbit(v)) for(int i = k ; i ; i -= lowbit(i)) temp = max(temp , tmax[v][i]) ; return temp ; } int main() { n = read() ; m = read() ; for(int i = 1 ; i <= n ; i ++) val[i] = read() , vmax = max(vmax , val[i]) ; for(int i = 1 ; i <= n ; i ++) for(int j = m , ret ; j >= 0 ; j --) { ret = query(val[i] + j , j + 1) + 1 ; Ans = max(Ans , ret) ; change(val[i] + j , j + 1 , ret) ; } printf("%d\n",Ans) ; return 0 ; }
[SCOI2014]方伯伯的玉米田