【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
",dp[tot][m]);
	return 0;
}
原文地址:https://www.cnblogs.com/zsyacm666666/p/7624307.html