前言
蓝桥杯的题目真的有点意思,题目的难度已经不低了(思维上不低,代码上还是比较简单的)
题目大意受篇幅限制,这里就不多说了。
正文
现在假设大家全部了解题意了。
首先,我们想到的应该是枚举每个人,然后看是否与其他人有冲突,但是这样的时间是爆炸的。这种方法我们就Pass掉了。
现在我们来思考一个问题,假设第一组里面有(0,k,2k,3k,4k,5k…),第二组里面有(1,1+k,1+2k,1+3k…)
这两组之间显然是没有冲突的,因为就算是最接近的差距也是(k±1),所以我们只需要在每组内部选择,因为各个组之间是独立的。
现在问题就转化成了,如何求在各个组内部的最大选择。
这显然就是一个dp问题啦!
dp[i]表示在每组中选择了前i个人的最大值,那么dp[i]和dp[i-1]就是冲突的,因为他们之间的差值是k,所以dp[i] = max(dp[i-1],dp[i-2]+val[i]),其中val[i]表示i这个人得分的个数,因为我们显然每次选择,都把全部该值选上,这样既不会冲突也可以保证最大值。
所以我们只要把序列分成k组,每次求各个组的最大值后,将其加入到ans内就可以啦!
注意讨论k==0的情况。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int dp[maxn];
int cnt[maxn];
int a[maxn];
int val[maxn];
int n,k;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
cnt[a[i]]++;
}
int ans = 0;
if(k==0)
{
for(int i=0;i<maxn;i++)
{
if(cnt[i]) ans++;
}
}
else
{
for(int i=0;i<k;i++)
{
int p = 0;
for(int j=i;j<maxn;j+=k)
{
val[p++] = cnt[j];
}
dp[0] = val[0];
for(int j=1;j<p;j++)
{
if(j==1) dp[j] = max(dp[0],val[j]);
dp[j] = max(dp[j-1],dp[j-2]+val[j]);
}
ans += dp[p-1];
}
}
printf("%d\n",ans);
return 0;
}