【笔记】区间DP
记录一些基础的区间
0x00 AT_dp_n N - Slimes
最板的区间
记
第一维从小到大枚举区间长度
其中
AC code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define mod 998244353
#define int long long
using namespace std;
int a[405],n,m,f[405][405],s[405];
signed main(){
IOS;TIE;
cin>>n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) cin>>a[i],f[i][i]=0,s[i]=s[i-1]+a[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
}
}
}
cout<<f[1][n]<<endl;
return 0;
}
双倍经验:P1775 石子合并(弱化版)
0x01 P1880 [NOI1995] 石子合并
来看常规版,也就是环上问题。
首先显然断环成链,把石子复制到两倍长,然后同时维护区间最大最小代价即可。最小要初始化为
注意区间长度最大仍取到
AC Code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define mod 998244353
using namespace std;
int n,a[205],s[205],fmx[205][205],fmn[205][205];
int ansmx,ansmn=1e9;
signed main(){
IOS;TIE;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[n+i]=a[i];
for(int i=1;i<=n*2;i++) s[i]=s[i-1]+a[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n*2;i++){
int j=i+len-1;
fmn[i][j]=1e9;
for(int k=i;k<j;k++){
fmx[i][j]=max(fmx[i][j],fmx[i][k]+fmx[k+1][j]+s[j]-s[i-1]);
fmn[i][j]=min(fmn[i][j],fmn[i][k]+fmn[k+1][j]+s[j]-s[i-1]);
}
}
}
for(int i=1;i<n;i++){
ansmx=max(ansmx,fmx[i][i+n-1]);
ansmn=min(ansmn,fmn[i][i+n-1]);
}
cout<<ansmn<<endl<<ansmx<<endl;
return 0;
}
0x02 P3146 [USACO16OPEN]248 G
同样是区间合并,记
其中判断条件意为两个相邻区间可以合成的数相同,但是不能为
不同的是答案不为
AC Code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define mod 998244353
using namespace std;
int n,a[255],f[255][255],ans;
signed main(){
IOS;TIE;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i],ans=max(ans,a[i]);
f[i][i]=a[i];
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
if(f[i][k]==f[k+1][j]&&f[i][k]){
f[i][j]=max(f[i][j],f[i][k]+1);
ans=max(ans,f[i][j]);
}
}
}
}
cout<<ans<<endl;
return 0;
}
0x03 P3147 [USACO16OPEN]262144 P
与上一题唯一的区别是数据范围,显然不能支持
巧妙的思路:设
初始化为对于每个输入的
借助一个样例理解:2 2 3
。假设我们已经知道
所以第一维枚举
AC Code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define mod 998244353
using namespace std;
int n,a,f[65][270005],ans;
signed main(){
IOS;TIE;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
f[a][i]=i+1;
}
for(int i=2;i<=60;i++){
for(int j=1;j<=n;j++){
if(!f[i][j]) f[i][j]=f[i-1][f[i-1][j]];
if(f[i][j]) ans=i;
}
}
cout<<ans<<endl;
return 0;
}
0x04 P4170 [CQOI2007]涂色
首先得知连续相同的一段颜色可以看做一个点。然后要分类讨论一下:
如果当前区间的两端点颜色相等,则转移只需要分别减掉左右端点取
否则就枚举断点,转移方程为
AC Code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define mod 998244353
using namespace std;
int n,x,a[55],f[55][55],lst=-1;
string s;
signed main(){
IOS;TIE;
cin>>s;
for(int i=0;i<s.size();i++){
x=s[i]-'A';
if(x!=lst) a[++n]=x,lst=x;
}
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) f[i][i]=1;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(a[i]==a[j]) f[i][j]=min(f[i+1][j],f[i][j-1]);
else{
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
}
cout<<f[1][n]<<endl;
return 0;
}
0x05 P2858 [USACO06FEB]Treats for the Cows G/S
与之前的区间合并不太一样,这次只需把一个点合入一段区间即可,所以不用枚举断点的一维。
但是每个点都有要乘一个权值。考虑倒着做。单点最后取的倍率为
设当前已取区间的长度为
AC Code
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define mod 998244353
using namespace std;
int n,a[2005],f[2005][2005];
signed main(){
IOS;TIE;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],f[i][i]=n*a[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j]=max(f[i][j-1]+a[j]*(n-len+1),f[i+1][j]+a[i]*(n-len+1));
}
}
cout<<f[1][n]<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!