P2135 方块消除 题解

P2135 方块消除

思路

这种肯定是区间 DP 题,转移就形如两个区间拼起来。但是发现转移显然有点假,因为题目还有一种情况是先消掉中间的,将两边两种颜色相同的拼起来再消掉。

考虑拼起来的过程是将两段或多段不相邻但是颜色相同的段夹在中间的先删掉,然后将其合并起来。

多段不相邻的东西怎么合并?这个确实比较困难,但是我们可以考虑一个类似背包的过程,我们先预知一下和多少个颜色相同的去合并,转移就是去凑颜色相同的位置。

具体的,设 \(f_{l,r,k}\) 表示将 \([l,r]\) 这一段区间合并后的最高得分,但是有 \(k\) 个与 \(a_r\) 颜色相同的数也参与了合并。有转移

\[\begin{aligned} f_{l,r,k}&\gets f_{l,r-1,0}+f_{r,r,k}\\ f_{l,r,k}&\gets f_{l,i,k+len_r}+f_{i+1,r-1,0}\times [col_i=col_r] \end{aligned} \]

第一条是好理解的。第二条的含义是 \(r\) 先不消,合并到 \([l,i]\) 上再去消除。
这个转移就可以将多个不连续但颜色相同的段合并到一起了。原理是比较自然的也就是将要合并到一起的颜色相同的段先贷款给小区间,然后让其后面的区间来还。

边界是 \(f_{i,i,k}=(len_i+k)^2\)。答案是 \(f_{1,n,0}\)

code

代码实现就比较简单了。

点击查看代码
#include<bits/stdc++.h>
bool Mbe;
using namespace std;
#define ll long long
//namespace FIO{
//	template<typename P>
//	inline void read(P &x){P res=0,f=1;char ch=getchar();while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}x=res*f;}
//	template<typename Ty,typename ...Args>
//	inline void read(Ty &x,Args &...args) {read(x);read(args...);}
//	inline void write(ll x) {if(x<0ll)putchar('-'),x=-x;static int sta[35];int top = 0;do {sta[top++] = x % 10ll, x /= 10ll;} while (x);while (top) putchar(sta[--top] + 48);}
//}
//using FIO::read;using FIO::write;
const int N=55,M=1005;
int n,f[N][N][M],cnt[N],col[N],m;
int pw(int x){return x*x;}
void Max(int &x,int y){x=max(x,y);}
bool Med;
signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n;for(int i=1;i<=n;i++)cin>>col[i];
    for(int i=1;i<=n;i++)cin>>cnt[i],m+=cnt[i];
    for(int i=1;i<=n;i++)for(int k=0;k<=m;k++)f[i][i][k]=pw(cnt[i]+k);
    for(int len=2;len<=n;len++){
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            for(int k=0;k<=m;k++){
                f[l][r][k]=f[l][r-1][0]+pw(cnt[r]+k);
                if(k+cnt[r]>m)continue;
                for(int i=l;i<r-1;i++){
                    if(col[i]==col[r]){
                        Max(f[l][r][k],f[l][i][k+cnt[r]]+f[i+1][r-1][0]);
                    }
                }
            }
        }
    }
    cout<<f[1][n][0]<<'\n';
    cerr<<'\n'<<1e3*clock()/CLOCKS_PER_SEC<<"ms\n";
    cerr<<'\n'<<fabs(&Med-&Mbe)/1048576.0<<"MB\n";
    return 0;
}
posted @ 2025-10-25 17:47  all_for_god  阅读(15)  评论(0)    收藏  举报