【HIHOCODER 1601】 最大得分(01背包)
描述
小Hi和小Ho在玩一个游戏。给定一个数组A=[A1, A2, ... AN],小Hi可以指定M个不同的值S1,S2, S3 ... SM,这样他的总得分是 ΣSi × count(Si)。(count(Si)是数组中与Si相等的元素的个数)。
为了增加难度,小Ho要求小Hi选择的S1..SM其中任意两个Si和Sj都满足|Si-Sj| > 1。
你能帮助小Hi算出他最大得分是多少吗?
输入
第一行包含两个整数N和M。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,1 ≤ M ≤ N ≤ 10 =
对于100%的数据,1 ≤ M ≤ N ≤ 1000 1 ≤ Ai ≤ 100000
输出
最大得分
样例输入
5 2
1 2 1 2 3
样例输出
5
题解
把每个数抽象为物品,拥有两个属性(数字和出现次数),通过值排序,\(a_i\)与\(a_{i-2}\)必然不冲突(距离>=2)
\(dp[i][j]\)为考虑到第i个,选择了j个的最大得分
转移方程看代码吧
#include <vector>
#include <queue>
#include <cstdio>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define inf 1000000000
#define PI acos(-1)
#define bug puts("here")
#define REP(i,x,n) for(int i=x;i<=n;i++)
#define DEP(i,n,x) for(int i=n;i>=x;i--)
#define mem(a,x) memset(a,x,sizeof(a))
typedef unsigned long long ull;
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void Out(int a){
if(a<0) putchar('-'),a=-a;
if(a>=10) Out(a/10);
putchar(a%10+'0');
}
const int N=1000+10;
ll a[N],vis[N*N],dp[N][N];
struct node{
int a,v;
}b[N];
int main()
{
int n=read(),m=read();
ll v=0;
REP(i,1,n){
a[i]=read();vis[a[i]]++;
v=max(v,a[i]);
}
int tot=0;
REP(i,1,v) if(vis[i]) b[++tot]=node{i,vis[i]};
REP(i,1,tot){
REP(j,1,m){
if(abs(b[i].a-b[i-1].a)>1||i==1)
dp[i][j]=max(dp[i-1][j-1]+b[i].a*b[i].v,dp[i-1][j]);
else dp[i][j]=max(dp[i-2][j-1]+b[i].a*b[i].v,dp[i-1][j]);
}
}
printf("%lld\n",dp[tot][m]);
return 0;
}