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;
}