蒟蒻来讲题,还望大家喜。若哪有问题,大家尽可提!
Hello, 大家好哇!本蒟蒻今天来讲一下AtCoder Beginner Contest 281的D题——Max Multiple
=============================================================================
Problem Statement
You are given a sequence of non-negative integers .
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
- 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了!
首先,我们设一下状态:
表示i个数中,选了j个数,且这j个数的和对d取余为c的所有这种组合中j个数的和的最大值
于是,最后输出的便是(不难看出)
其次,我们再来设初值:
因为题目中说若没有方案,则输出-1。所以我们可以先把所有的方案设为-1。不过,就是0。
最后,我们推一下状态转移方程:
当第i个数取与不取对dp的影响如下:
①时,直接跳过;
②当不取时,,我们有当前状态转移到下一个状态,因为不取所以就与一样,所以将其本身与求最大值即可!
③当取且j<k时,
因为取,所以数量+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;
}
好了,今天就到这里啦!
本初中生蒟蒻时间紧迫,临近期末写一篇不容易——麻烦喜欢的点个赞,关个注,谢谢!~