AT_s8pc_5_f Lunch Menu
题意
给你一个
题解
对于每个区间,我们只关注最大值,所以我们从大到小考虑每一个数是否变
当一个数保留时,我们可以立即处理跨过这个点的所有区间。那么就能将一个大问题分解成两个小问题。
比如当我们处理
维护一下上一次保留哪个数和还剩几次操作次数,然后记忆化搜索即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=55;
int n,m,q,a[N],cnt[N][N][N],b[N];
ll f[N][N][N][N];
ll dfs(int l,int r,int x,int y){
if(y>=r-l+1||l>r)return 0;
if(~f[l][r][x][y])return f[l][r][x][y];
int t=x;
while(t<=n&&(b[t]<l||r<b[t]))t++;
if(t>n)return 0;
f[l][r][x][y]=1e18;
//save
for(int i=0;i<=y;i++)f[l][r][x][y]=min(f[l][r][x][y],dfs(l,b[t]-1,x,i)+dfs(b[t]+1,r,x,y-i)+1ll*cnt[b[t]][l][r]*a[b[t]]);
//delete
if(y)f[l][r][x][y]=min(f[l][r][x][y],dfs(l,r,t+1,y-1));
return f[l][r][x][y];
}
bool cmp(int x,int y){return a[x]>a[y];}
int main(){
memset(f,-1,sizeof(f));
cin>>n>>m>>q;
for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=i;
sort(b+1,b+n+1,cmp);
for(int i=1,l,r;i<=q;i++){
scanf("%d%d",&l,&r);
for(int j=l;j<=r;j++){
for(int L=1;L<=l;L++){
for(int R=r;R<=n;R++){
cnt[j][L][R]++;
}
}
}
}
cout<<dfs(1,n,1,m);
}