【蓝桥杯有点意思】第八届蓝桥杯决赛 对局匹配 分组+dp

题目链接戳这里

前言

蓝桥杯的题目真的有点意思,题目的难度已经不低了(思维上不低,代码上还是比较简单的)
题目大意受篇幅限制,这里就不多说了。


正文

现在假设大家全部了解题意了。

首先,我们想到的应该是枚举每个人,然后看是否与其他人有冲突,但是这样的时间是爆炸的。这种方法我们就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;
}

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/87913175