洛谷P4158 [SCOI2009] 粉刷匠 题解

所有的 DP ,只要式子一推出来(不管复杂度),那就很简单了,因为优化是成千上万种的……

思路1:

我们考虑设 f[i][j][k] 表示:当前 DP 到第 i 块木板的第 j 个位置,共涂了 k 次,所能获得的最大收益。因为还要枚举当前这次涂是从哪到哪的,因此复杂度为 O(NM2T) ,实际 90% 。在实际操作中,第一维可以省略。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110;
const int M=5e3+100;
int n,m,t,ans;
int f[N][M],res[N][N][2];
char s[N];
inline int read(){
	char c=getchar();int f=1,x=0;
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int main(){
    n=read();
    m=read();
    t=read();
    for(int l=1;l<=n;l++){
        scanf("%s",s+1);
        for(int i=1;i<=m;i++){
        	for(int j=i;j<=m;j++){
        		res[i][j][0]=res[i][j-1][0]+(s[j]=='0');
				res[i][j][1]=res[i][j-1][1]+(s[j]=='1');
			}
		}
        for(int i=0;i<=t;i++) f[0][i]=f[m][i];
        for(int i=1;i<=m;i++){
            for(int j=1;j<=t;j++){
                f[i][j]=0;
                for(int k=0;k<i;k++) f[i][j]=max(f[i][j],f[k][j-1]+max(res[k+1][i][0],res[k+1][i][1]));
            }
        }
    }
    for(int i=1;i<=t;i++) ans=max(ans,f[m][i]);
    printf("%d\n",ans);
    return 0;
}

虽然开个 O2 甚至只是单纯卡卡长也一样能过,但是介于十年前评测姬的蜜汁速度,我们思考还有没有优化复杂度的余地。

思路2:

我们考虑设 f[i][j][k][0/1/2] 表示:

当前 DP 到第 i 块木板的第 j 个位置,共涂了 k 次,当前这个位置的状态是 0/1/2

其中,状态 0 意为涂上了颜色 0 ,状态 1 意为涂上了颜色 1 ,状态 2 意为啥也没涂。

因为这种方法不需要枚举上一次的断点,因此复杂度是 O(NMT) 的。老样子,第一维可以砍掉。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110;
const int M=5e3+100;
int n,m,t,ans;
int f[N][M][3];
char s[N];
inline int read(){
	char c=getchar();int f=1,x=0;
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int main(){
    n=read();
    m=read();
    t=read();
    for(int l=1;l<=n;l++){
        scanf("%s",s+1);
        for(int i=0;i<=t;i++) f[0][i][2]=max(max(f[m][i][0],f[m][i][1]),f[m][i][2]);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=t;j++){
                f[i][j][2]=max(max(f[i-1][j][0],f[i-1][j][1]),f[i-1][j][2]);
                f[i][j][1]=max(max(f[i-1][j-1][0],f[i-1][j][1]),f[i-1][j-1][2])+(s[i]=='0');
                f[i][j][0]=max(max(f[i-1][j][0],f[i-1][j-1][1]),f[i-1][j-1][2])+(s[i]=='1');
            }
        }
    }
    for(int i=1;i<=t;i++) ans=max(max(ans,f[m][i][0]),max(f[m][i][1],f[m][i][2]));
    printf("%d\n",ans);
    return 0;
}
posted @   xuantianhao  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示