倍数问题
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。
但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。
现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。
数据保证一定有解。
输入格式
第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。
输出格式
输出一行一个整数代表所求的和。
数据范围
1≤n≤105,
1≤K≤103,
给定的 n 个数均不超过 108
输入样例:
4 3
1 2 3 4
输出样例:
9
这显然是一道背包问题,即从一些数中选择一些数的问题,下面是闫氏dp分析法:
既然已经分析完了,那么代码就好写了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1010,M=3*N;
const int INF=2e9;
vector<int> a[N];
int f[4][N];
int g[4][N];
int n,m;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
a[x%m].push_back(x);
}
memset(f,-0x3f,sizeof f);//一个都不选的话,余数为其它值的情况不存在,因此总和赋值为负无穷,因此初始化为负无穷,这样后面max操作会自动把它过滤掉
f[0][0]=0;//一个不选的话,余数为0,总和也为0
for(int op=0;op<m;op++)
{
sort(a[op].begin(),a[op].end());
reverse(a[op].begin(),a[op].end());
for(int i=0;i<3&&i<a[op].size();i++)
{
int w=a[op][i];
for(int j=3;j>=1;j--)
{
for(int k=0;k<m;k++)
f[j][k]=max(f[j][k],f[j-1][(k-w%m+m)%m]+w);
}
}
}
cout<<f[3][0];
return 0;
}