CF1866D 题解

前言

都是状态数 O(n2m) 的 DP,我发个 O(nm) 的。

题解

首先不难注意到如下事实:

我们称“第 i 列的矩形”为,以第 i 列开头的矩形。

我们只考虑前 i 列以内的数,假设前 i 列选了 j 个数(ji)。

那么一定有 j 个矩形选了数。

可以证明,存在一种方式,使得恰好第 1j 列的矩形选了数,第 j+1 到第 i 列的矩形不选数。

考虑数学归纳法,读者自证不难。

我们先对每一列的数降序排序,计算其以列为单位的前缀和,第 i 列前 j 大数的和记为 ai,j

可以设计以下 DP:

fi,j 表示在前 i 列中选数,能覆盖到第 i+1 列的空闲矩形一共有 j 个。

转移时枚举第 i+1 列矩形选了 l 个数,则有:

fi+1,j+1lfi,j+ai+1,l

注意上式只对 imk 成立,因为从 i=mk+1 列开始,第 i+1 列没有新的矩形,所以对于 i>mk,有:

fi+1,jlfi,j+ai+1,l

直接 DP,时间复杂度 O(n2m),空间复杂度如果采用滚动数组可以优化到 O(n),以下代码为了方便阅读没有采用滚动数组。

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=20,M=1e5+10,INF=0x3f3f3f3f3f3f3f3f;
int n,m,k;
int a[M][N];
int f[M][N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>a[j][i];
	for(int i=1;i<=m;i++)sort(a[i]+1,a[i]+1+n,greater<int>());
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			a[i][j]+=a[i][j-1];
	memset(f,-0x3f,sizeof(f));
	f[0][0]=0;
	for(int i=0;i<=m-k;i++)
		for(int j=0;j<k;j++)
			for(int l=0;l<=j+1;l++)
				f[i+1][j+1-l]=max(f[i+1][j+1-l],f[i][j]+a[i+1][l]);
	for(int i=m-k+1;i<m;i++)
		for(int j=0;j<=m-i;j++)
			for(int l=0;l<=j;l++)
				f[i+1][j-l]=max(f[i+1][j-l],f[i][j]+a[i+1][l]);
	cout<<f[m][0]<<endl;
	return 0;
}
posted @   Linge_Zzzz  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示