朝题夕解之动态规划(2)

简介: 朝题夕解之动态规划(2)

题目描述(题目难度:简单)

由于在维护世界和平的事务中做出巨大贡献,Dzx被赠予糖果公司2010年5月23日当天无限量糖果免费优惠券。
在这一天,Dzx可以从糖果公司的 N 件产品中任意选择若干件带回家享用。
糖果公司的 N 件产品每件都包含数量不同的糖果。
Dzx希望他选择的产品包含的糖果总数是 K 的整数倍,这样他才能平均地将糖果分给帮助他维护世界和平的伙伴们。
当然,在满足这一条件的基础上,糖果总数越多越好。
Dzx最多能带走多少糖果呢?
注意:Dzx只能将糖果公司的产品整件带走。
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行 1 个整数,表示糖果公司该件产品中包含的糖果数目,不超过 1000000。
输出格式
符合要求的最多能达到的糖果总数,如果不能达到 K 的倍数这一要求,输出 0。
数据范围
1≤N≤100,
1≤K≤100,
输入样例:
5 7
1
2
3
4
5
输出样例:
14
样例解释
Dzx的选择是2+3+4+5=14,这样糖果总数是7的倍数,并且是总数最多的选择。

解题报告


题意理解


注意一件产品中是有若干个糖果,现在需要实现的是获得尽可能多的糖果并且糖果总数要是k的倍数。因此顺势将我们的状态表示f [ i , j f[i,jf[i,j]定义彻底清楚:

f ( i , j ) f(i, j)f(i,j)代表前i ii个物品的总价值 % k = j \%k=j%k=j 的集合,在这里限制是关于 % k \%k%k余数是多少


DP分析


因为对于每件糖果只有拿和不拿两种选择,进而可以直接抽象为一个01背包问题

微信图片_20221018141027.jpg

对于不包含物品i ii的情况:集合都不包括第i ii个物品,表示的意义就是前i − 1 i−1i−1个物品,%k=j的集合:f ( i − 1 , j ) f(i−1,j)f(i−1,j)

对于包含物品i ii的情况:集合都包括第i ii个物品,这个时候,可以将这个集合拆分成为不包含i ii的板块加上这个一定存在的i ii的板块,就可以表示为,也从前i − 1 i-1i−1个中选择,同时在总和j jj中剔除i ii的糖果总数w [ i ] w[i]w[i],将这个w [ i ] w[i]w[i]单独加上,因为集合维护的是 总 价 值 % k = j 总价值\%k = j总价值%k=j,故追加上一个% k \%k%k。


注意事项——c++中负数取模的处理


转移方程中的( j − w [ i ] ) (j−w[i])%k)(j−w[i])可能为负的,必须要将余数变成[ 0 , n − 1 ] [0,n−1][0,n−1]之间,所以c++负数取余要变成( ( j − w [ i ] ) % k + k ) % k ((j−w[i])\%k+k)\%k((j−w[i])%k+k)%k。

可以简单粗暴的记作加值模值


1.假如( j − w [ i ] > = 0 ) (j - w[i] >= 0)(j−w[i]>=0),由于k % k = 0 k\%k=0k%k=0,所以不会影响。


2.假如( j − w [ i ] < 0 ) (j - w[i] < 0)(j−w[i]<0), 带个负数进去试下就可以验证,在这里+ k +k+k可以使( j − w [ i ] ) % k (j - w[i]) \%k(j−w[i])%k变成[ 0 , n − 1 ] [0,n-1][0,n−1]之间,再取余仍然是[ 0 , n − 1 ] [0,n-1][0,n−1]之间。


参考代码

//所有从前i个物品中选择,总和除以k的余数是j的方案的集合
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int n, k;
int f[N][N];//一般第一维是数量,第二维是限制。这里的第二维就代表选取的总和最大的方案
int main(){
    scanf("%d%d", &n, &k);
    memset(f, -0x3f, sizeof f);//f[0][1]、f[0][2]···无意义,把这些非法方案初始化为负无穷
    f[0][0] = 0;            //本题求的是最大值而不是方案数,因此为0
    for(int i = 1; i <= n; i ++){
        int w;
        scanf("%d", &w);
        for(int j = 0; j <= k; j ++){
            f[i][j] =f[i-1][j];
            f[i][j] = max(f[i][j], f[i - 1][((j - w) % k + k ) % k] + w);
        }
    }
    printf("%d\n", f[n][0]);
    return 0;
}


相关文章
|
JavaScript
VUE~富文本简单使用~tinymce
VUE~富文本简单使用~tinymce
1071 0
VUE~富文本简单使用~tinymce
|
网络协议 Java 测试技术
阿里内部Netty实战小册,值得拥有
Netty 是一个高性能的 Java 网络通信框架,简化了网络编程并涵盖了最新的Web技术。它提供了一种抽象,降低了底层复杂性,使得更多开发者能接触网络编程。Netty 因其易用性、高效性和广泛的应用场景受到推崇,适合互联网行业从业者学习,有助于理解和开发基于Netty的系统。免费的《Netty实战小册》详细介绍了Netty的各个方面,包括概念、架构、编解码器、网络协议和实际案例,帮助读者深入理解和应用Netty。如需完整版小册,可点击链接获取。
阿里内部Netty实战小册,值得拥有
|
druid Java
Failed to bind properties under 'spring.datasource' to javax.sql.DataSource:
Failed to bind properties under 'spring.datasource' to javax.sql.DataSource:
1046 0
Failed to bind properties under 'spring.datasource' to javax.sql.DataSource:
|
人工智能 自动驾驶 机器人
云栖Day1重磅合集! Qwen2.5-72B成为全球最强开源模型
今天,2024云栖大会正式开幕 通义千问重磅开源Qwen2.5 性能超越Llama 405B 继续稳居最强开源大模型位置
1063 9
|
SQL 关系型数据库 MySQL
ETL工具 Kettle 中怎么通过变量传参
ETL工具 Kettle 中怎么通过变量传参
1072 0
|
存储 算法 数据库
常用的c++序列化方法
常用的c++序列化方法
279 0
|
SQL 运维 监控
MySQL死锁系列-线上死锁问题排查思路
本篇文章会讲解一下如果线上发生了死锁异常,如何去排查和处理。除了系列前文讲解的有关加锁和锁冲突的原理还,还需要对 MySQl 死锁日志和 binlog 日志进行分析。
MySQL死锁系列-线上死锁问题排查思路
|
5G 网络架构
5G 系统网络架构 | 带你读《5G 无线系统设计与国际标准》之四
为了适应各种部署场景,5G 支持了两种部署方式:一种为分布式部署,这种方式与 LTE系统类似,网络由基站组成,基站支持全协议栈的功能;另一种为集中式部署,基站进一步分为集中单元(CU,Centralized Unit)和分布单元(DU,Distributed Unit)两个节点,CU 和 DU 分别支持不同的协议栈和功能,
5G 系统网络架构  | 带你读《5G 无线系统设计与国际标准》之四
|
Kubernetes 网络协议 Cloud Native
云原生|kubernetes|kubeadm五分钟内部署完成集群(完全离线部署---适用于centos7全系列)(二)
云原生|kubernetes|kubeadm五分钟内部署完成集群(完全离线部署---适用于centos7全系列)
696 0