ABC345E
不得不说这道 dp
既考察对时间复杂度方面的优化,也要考虑对空间方面的优化。
题意
首先从暴力说起:
首先既然让我们删除
显然可以 dfs
枚举子集加剪枝优化(不过剪不剪的好像没啥区别),这样做是
代码:
//tomxi
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
bitset<N> v;
int val[N],mx=-1,col[N],n,k;
inline void dfs(int x,int K){
if(K>k) return;
if(K+(n-x+1)<k) return;
if(x==n+1){
if(K!=k) return;
int pos=-1,s=0;
for(int i=1;i<=n;i++){
if(v[i]){
if(col[i]==pos) return;
pos=col[i];
s+=val[i];
}
}
mx=max(mx,s);
return;
}
for(int i=0;i<=1;i++){
v[x]=i;
dfs(x+1,K+(!i));
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>col[i]>>val[i];
dfs(1,0);
cout<<mx;
return 0;
}
//tomxi
发现如果一个数选肯定是比不选要优的所以我们可以考虑尽可能的选第 dp
。
暴力的 dp
:
一个最最最暴力的做法就是定义
代码:
//tomxi
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e3+5;
const int K=2e3+5;
int f[N][K];
int col[N],val[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n,k;
cin>>n>>k;
int maxn=0,tm=0;
for(int i=1;i<=n;i++) cin>>col[i]>>val[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=n-k;j++){
maxn=0;int stm=1;
f[i][j]=val[i];
for(int p=1;p<i;p++){
if(col[p]!=col[i])maxn=max(maxn,f[p][j-1]);
if(col[p]!=col[i]) stm++;
}
tm=max(tm,stm);
f[i][j]+=maxn;
}
}
int mx=0;
if(tm<n-k){
cout<<-1;return 0;
}
for(int i=1;i<=n;i++) mx=max(mx,f[i][n-k]);
cout<<mx;
return 0;
}
//tomxi
时间复杂度方面优化 dp
:
其实我们发现我们选的区间都是连续的区间,因此可以考虑用数据结构来优化它,固然考虑线段树,但是因为如果最大值的 col[]
与 col[i]
相同的话就要考虑使用次大值了,这样做的话要考虑区间最大值和严格区间次大值,处理起来相当麻烦,关键是还过不了,时间复杂度是
但其实并不需要这么麻烦,在仔细观察一下,可以发现所取的区间不光是连续的,而且还是从 1
到 i
的,因此我们可以用两个变量来储存所对应的最大值,次大值,最大值的位置,次大值的位置。
空间方面的优化 dp
:
因为
代码:
//tomx
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N=2e5+5;
int n,k,col[N],val[N];
ll f[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>k;
for(int x=1;x<=n;++x) cin>>col[x]>>val[x];
memset(f,-1e18,sizeof(f));
for (int y=1;y<=n-k;++y) {
ll m=f[y-1],_m=-1e18;
int cm=col[y-1];
for (int z=y;z<=y+k;++z){
ll M=f[z];
if(col[z]!=cm) {
f[z]=m+val[z];
if(M>=m){
_m=m,m=M,cm=col[z];
}else if(M>_m){
_m=M;
}
}else{
f[z]=_m+val[z];
if(M>m){
m=M;
}
}
}
}
ll ans=-1;
for(int i=n-k;i<=n;++i) {
ans=max(ans,f[i]);
}
cout<<ans;
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!