CF1866D Digital Wallet

传送门

题意

给你一个 n × m n \times m n×m 的矩阵,让你从 1 1 1 k k k 列, 2 2 2 k + 1 k+1 k+1 列, 3 3 3 k + 2 k+2 k+2 列…… m − k + 1 m-k+1 mk+1 m m m 列中各选一个数(不可以重复选择),要你求出这些选出来的数的最大值。

思路

一眼动态规划,第一维枚举这是第几列,第二维枚举目前这一列中的第几个数,第三维枚举之前已选择的数的个数。

因为每一列最多可以被选择 k k k 次,为了保证此列在可选择的范围内,每一次选数时的起点必须大于等于 i − k + 1 i-k+1 ik+1 列,所以只需从 i − k + 1 i-k+1 ik+1 找到 i i i 即可,由于本蒟蒻是枚举的选择这个数前的选择数目,所以是 从 i − k i-k ik i − 1 i-1 i1

为了保证每个数只选择一次,要从后往前找,有点类似背包的思想。

状态转移方程: d p [ p + 1 ] = max ⁡ ( d p [ p ] + a [ j ] [ i ] , d p [ p + 1 ] ) dp[p+1]=\max(dp[p]+a[j][i],dp[p+1]) dp[p+1]=max(dp[p]+a[j][i],dp[p+1])

其中, p p p 指之前已选择的数的数量, a [ j ] [ i ] a[j][i] a[j][i] 表示矩阵中第 j j j 行,第 i i i 列的数,时间复杂度为 O ( m n k ) O(mnk) O(mnk)

AC 代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,dp[100005]={0},a[15][100005],o=0;
signed main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int p=i-1;p>=max(i-k,o);p--)
			{
				dp[p+1]=max(dp[p]+a[j][i],dp[p+1]);
			}
		}
	}
	cout<<dp[m-k+1];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值