#1601 : 最大得分
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小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
题目中要求|Si-Sj| > 1,一开始以为是不相等。
解题思路:先统计每个数的值Si × count(Si),之后再进行一次动态规划,dp[i][j]表示,从0-i恰好选取j+1个不冲突数的最大值。
当然,最终选取的数量可能不是m个。另外,最终int32位有可能会溢出,所以建议使用int64。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int MX=1000+100;
int n,m;
int a[MX];
ll dp[MX][MX];
vector<P> ans;
int main()
{
while(cin>>n>>m)
{
ans.clear();
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
a[n]=0;
int cnt=1;
for(int i=0;i<n;i++)
{
if(a[i]==a[i+1])
cnt++;
else
{
ans.push_back(P( cnt*a[i],a[i]) );
// cout<<ans[ans.size()-1].first<<" "<<ans[ans.size()-1].second<<endl;
cnt=1;
}
}
dp[0][0]=ans[0].first;
n=ans.size();
for(int i=1;i<n;i++) dp[i][0]=max((ll)ans[i].first,dp[i-1][0]);
for(int j=1;j<m;j++)
{
for(int i=j;i<n;i++)
{
if(ans[i].second==ans[i-1].second+1)
{
dp[i][j]=dp[i-1][j];
if(i>=2)
dp[i][j]=max(dp[i-1][j],dp[i-2][j-1]+ans[i].first);
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+ans[i].first);
}
}
}
ll res=0;
for(int i=0;i<m;i++) res=max(res,dp[n-1][i]);
cout<<res<<endl;
}
return 0;
}