【区间 dp】AcWing 322. 消木块
思路比较有新意的区间 dp。
分析
直接用 表示删除区间 的最大收益会发现无法正确处理删除后出现同色木块合并对应的贡献。
那我们考虑用更复杂的状态表示来维护之。
发现一个区间的右端点终究会有一个时候被删掉,所以利用其来进行状态转移。
我们用 表示 区间,在 右边与 相连的同色 木块的个数为 (即 )的状态的最大收益。
那么就枚举一下 在与前面哪个与其同色的块合并然后求个 就好了,当然也不要忘了不与前面合并的情况。(详细见下面转移方程)
转移方程为:
// Problem: 消木块
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/324/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
inline void read(int &x){
int s=0; x=1;
char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
const int N=220;
int n, w[N];
int f[N][N][N];
int dp(int l, int r, int co){
int &res=f[l][r][co];
if(~res) return res;
if(l>r) return res=0;
res=dp(l, r-1, 0)+(1+co)*(1+co);
rep(k,l,r-1) if(w[k]==w[r]){
res=max(res, dp(l, k, 1+co)+dp(k+1, r-1, 0));
}
return res;
}
int main(){
int cs; cin>>cs;
int ks=0;
while(cs--){
cout<<"Case "<<(++ks)<<": ";
cin>>n;
rep(i,1,n) read(w[i]);
memset(f, -1, sizeof f);
cout<<dp(1, n, 0)<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】