CF1866D 题解
前言
都是状态数 的 DP,我发个 的。
题解
首先不难注意到如下事实:
我们称“第 列的矩形”为,以第 列开头的矩形。
我们只考虑前 列以内的数,假设前 列选了 个数()。
那么一定有 个矩形选了数。
可以证明,存在一种方式,使得恰好第 到 列的矩形选了数,第 到第 列的矩形不选数。
考虑数学归纳法,读者自证不难。
我们先对每一列的数降序排序,计算其以列为单位的前缀和,第 列前 大数的和记为 。
可以设计以下 DP:
设 表示在前 列中选数,能覆盖到第 列的空闲矩形一共有 个。
转移时枚举第 列矩形选了 个数,则有:
注意上式只对 成立,因为从 列开始,第 列没有新的矩形,所以对于 ,有:
直接 DP,时间复杂度 ,空间复杂度如果采用滚动数组可以优化到 ,以下代码为了方便阅读没有采用滚动数组。
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】