D - Max Multiple(AtCoder Beginner Contest 281)

蒟蒻来讲题,还望大家喜。若哪有问题,大家尽可提!

Hello, 大家好哇!本蒟蒻今天来讲一下AtCoder Beginner Contest 281的D题——Max Multiple

=============================================================================

Problem Statement

You are given a sequence of non-negative integers A=(a_{1},a_{2},...,a_{N}).

Let S be the set of non-negative integers that can be the sum of K terms in A (with distinct indices).

Find the greatest multiple of D in S. If there is no multiple of D in S, print -1 instead.

Constraints

  • 1\leq K\leq N\leq 100
  • 1\leq D\leq 100
  • 0\leq a_{i}\leq 10^{9}
  • All values in the input are integers.

Input

The input is given from Standard Input in the following format:

N K D
a1 ... aN

Output

Print the answer.


Sample Input 1

4 2 2
1 2 3 4

Sample Output 1

6

Here are all the ways to choose two terms in AA.

  • Choose a1 and ​a2, whose sum is 1+2=3.
  • Choose a1​ and a3​, whose sum is 1+3=4.
  • Choose a1​ and a4​, whose sum is 1+4=5.
  • Choose a2​ and a3​, whose sum is 2+3=5.
  • Choose a2​ and a4​, whose sum is 2+4=6.
  • Choose a3​ and a4​, whose sum is 3+4=7.

Thus, we have S={3,4,5,6,7}. The greatest multiple of 2 in S is 6, so you should print 6.


Sample Input 2

3 1 2
1 3 5

Sample Output 2

-1

In this example, we have S={1,3,5}. Nothing in S is a multiple of 2, so you should print -1.


主要意思

给你一个n, k, d, 以及一个数组a。问你:当a中k个数的和是d的倍数时, 这k个数和最大是多少?


思路1(没AC)

这个题可能起初想到的就是dfs或其他暴力方法,不过很不幸——听取TLE一片~~~(qwq)

但是本蒟蒻还是放出dfs代码吧!

DFS代码(此方法会TLE!!!)

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e2 + 10;

LL a[N];
LL path[N];
bool st[N];
LL mx = -1;
LL n, r, tmp, d;

void dfs(LL u,LL tmp, LL tt){
	if (u > r){
		if (tt % d == 0)
			mx = max(tt, mx);
		return;
	}
	else {
		for (int i = tmp; (r - u) + i <= n; i ++){
			if (!st[i]){
				st[i]=1;
				dfs(u+1,i+1, tt + a[i]);
				st[i]=0;
			}
		}
	}
}
int main(){
	cin>> n >> r >> d;
	
	for (int i = 1; i <= n; i ++)
		cin >> a[i];
	
	dfs(1, 1, 0);
	
	cout << mx << endl;

	return 0;
}

思路二(AC)


这题就只好用我们的老大难DP了!

首先,我们设一下状态: 

dp[i][j][c]

表示i个数中,选了j个数,且这j个数的和对d取余为c的所有这种组合中j个数的和的最大值

于是,最后输出的便是dp[n][k][0](不难看出)

其次,我们再来设初值

因为题目中说若没有方案,则输出-1。所以我们可以先把所有的方案设为-1。不过,dp[0][0][0]就是0。

最后,我们推一下状态转移方程:

当第i个数a_{i}取与不取对dp的影响如下:

dp[i][j][c] == -1时,直接跳过;

②当a_{i}不取时,dp[i+1][j][c] = max(dp[i + 1][j][c], dp[i][j][c]),我们有当前状态转移到下一个状态,因为不取所以dp[i+1][j][c]就与dp[i][j][c]一样,所以将其本身与dp[i][j][c]求最大值即可!

 ③当a_{i}取且j<k时, dp[i+1][j+1][(c+a_{i})%d] = max(dp[i+1][j+1][(c+a_{i})%d], dp[i][j][c] + a_{i})

因为a_{i}取,所以数量+1(即i+1),选的数+1(即j+1),余数变为余数+这个数再取余(即(c+ai)%d)

DP代码(AC)

#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;

const int N = 1e2 + 10;

int n, m, d;
LL dp[N][N][N], a[N];

int main()
{
	cin >> n >> m >> d;
	
	for (int i = 0; i < n; i ++)
		cin >> a[i];
	
    //初始化
	memset(dp, -1, sizeof dp);
			
	dp[0][0][0] = 0;
	
    //dp
	for (int i = 0; i < n; i ++)
		for (int j = 0; j <= m; j ++)
			for (int c = 0; c < d; c ++)
			{
				if (dp[i][j][c] == -1) continue;//第一种情况
				dp[i + 1][j][c] = max(dp[i][j][c], dp[i + 1][j][c]);//第二种情况
				if (j < m) dp[i + 1][j + 1][(c + a[i]) % d] = max(dp[i + 1][j + 1][(c + a[i]) % d], dp[i][j][c] + a[i]);//第三种情况
			}
	
	cout << dp[n][m][0];
	return 0;
}

好了,今天就到这里啦!

本初中生蒟蒻时间紧迫,临近期末写一篇不容易——麻烦喜欢的点个赞,关个注,谢谢!~

!!!蛰龙已惊眠,一啸动千山!!!

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值