题目中只有积分差为k的才不能同时选,那么也就是和当前状态下只有差为k的才能产生相互影响,别的就没有一点影响了,那么我们把能够相互影响的找出来,在每一组相互影响的里面找到最大值,在将每组的最大值加起来,就是最终的结果
在一组相互影响的里面,当前状态j只有两种,一种是选这个,另一种是不选这个,如果选的话dp[j] = dp[j-2] + cnt[j] (cnt表示j状态的数量),不选择的话:dp[j] = dp[j-1],那么最终的状态转移方程为dp[j] = max(dp[j-1],dp[j-2] + cnt[j])
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <algorithm> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int MAXN = 101000; int a[MAXN],num[MAXN],n,k; int cnt[MAXN]; int dp[MAXN]; //dp[i][0]:表示不选当前分数的情况 dp[i][1]:选择当前分数的情况 bool vis[MAXN]; int main() { int max_num = 0; memset(cnt,0,sizeof(cnt)); memset(dp,0,sizeof(dp)); memset(vis,false,sizeof(vis)); scanf("%d%d",&n,&k); for(int i =1 ;i <= n;i ++) { scanf("%d",&a[i]); cnt[a[i]] ++; max_num = a[i] > max_num?a[i]:max_num; } if(k == 0) { int ans = 0; for(int i = 0;i <= max_num;i ++) if(cnt[i]) ans ++; printf("%d\n",ans); } else { int ans = 0; sort(a+1,a+1+n); int index = 0; num[index++] = a[1]; //得到不重复的输入序列,0~index 他们分别对应的个数为cnt[num[i]] for(int i = 2;i <= n;i ++) { if(num[index-1] != a[i]) num[index++] = a[i]; } int pos,temp[MAXN]; for(int i = 0;i < index;i ++) { pos = 0; if(vis[num[i]] == false) { int p = num[i]; while(1) //从这个元素向后寻找相差大小等于k的一系列数组 { temp[pos++] = p; vis[p] = true; if(cnt[p + k] == 0) break; //不存在这个数了 p = p + k; //temp里面存储的是当前对应位置上的数字 } } if(pos == 1) ans += cnt[temp[0]]; else if(pos >= 2) { dp[0] = cnt[temp[0]],dp[1] = max(dp[0],cnt[temp[1]]); for(int j = 2;j < pos;j ++) dp[j] = max(dp[j-1],dp[j-2] + cnt[temp[j]]); ans += dp[pos-1]; } } printf("%d\n",ans); } }
文章来源: 蓝桥杯_历届试题 对局匹配