P3287 [SCOI2014] 方伯伯的玉米田

sad_lin發表於2024-11-11

P3287 [SCOI2014] 方伯伯的玉米田

感覺其實也不難。

我們必然知道選擇加區間的右端點是 \(n\),因為如果只選中間的話會與後面相差開,不如直接選上右,因為有兩個變數,位置與操作次數,所有我們就設狀態為 \(f_{x,k}\) 為我們 \(x\) 為左端點被加 \(k\) 次的最長不下降子序列,此時我們的樹狀陣列也要開兩維同樣記錄,查詢時也兩維查詢。

#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
const int N=1e4+10;
const int mod=1e9+7;
using namespace std;
int n,k;
int a[N];
int f[N][505];
int t[N][505];

int lb(int x){
	return x&-x;
}
void change(int x,int y,int z){
	for(int i=x;i<=5500;i+=lb(i)){
		for(int j=y;j<=k+1;j+=lb(j)){
			t[i][j]=max(t[i][j],z);
		}
	}
}
int query(int x,int y){
	int ans=0;
	for(int i=x;i;i-=lb(i)){
		for(int j=y;j;j-=lb(j)){
			ans=max(ans,t[i][j]);
		}
	}
	return ans;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=k;j>=0;j--){
			f[i][j]=query(a[i]+j,j+1)+1;
			change(a[i]+j,j+1,f[i][j]);
		} 
	}
	cout<<query(5500,k+1);
	return 0; 
}

相關文章