问题描述
小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K,系统都不会将他们匹配。
现在小明知道这个网站总共有N名用户,以及他们的积分分别是A1, A2, ... AN。
小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来(任意两名用户积分差不等于K)?
输入格式
第一行包含两个个整数N和K。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,1 <= N <= 10
对于100%的数据,1 <= N <= 100000, 0 <= Ai <= 100000, 0 <= K <= 100000
输出格式
一个整数,代表答案。
样例输入
10 0
1 4 2 8 5 7 1 4 2 8
样例输出
6
题目分析:
首先在输入这n个分数的同时,用数组 book[ ] 和map来统计每个分数出现的次数。
当k=0时情况比较特殊。
例如样例1中:
n=10,k=0,对于分数1 4 2 8 5 7 1 4 2 8 求分数差 不为0 的最多人数是:1,2,4,8,5,7即每个分数只匹配一位。这样只需要求map的大小就可以了。
当k!=0时:需要用到动态规划来做。
例如: k=2,对于分数1 4 2 8 5 7 1 4 2 8,我们将其分为K组,每一组相邻两个分数差为K,即-------第一组:分数段:0 2 4 6 8
次数段arr[ ]={ 0 ,2 ,2 ,0 ,2 }(每个分数出现的次数)
第二组:分数段: 1 3 5 7 9
次数段:2 0 1 1 0
这样我们在进行选择时,保证不选择相邻的次数就好了,而选择相邻次数中的哪一个就需要用到动规来做:
这里我先总结一下动态规划转移方程,很容易看懂:
dp[i]=arr[i] i==0
dp[i]=max(dp[i-1],arr[i]) i==1
dp[i]=max(dp[i-1],dp[i-2]+arr[i]) i>1
这样第一组动规后的结果为:dp[ ]={0,2,2,2,4} dp[i]就表示前i个人能取得的最多人数
第二组动规后的结果为:dp[ ]={2,2,3,3,3}
取得每一组动规结果的最后一个数相加就是我们要的结果了,这里就是4+3=7;
#include<iostream>
#include<map>
using namespace std;
int book[100005],a[100005],dp[100005];
map<int,int> mp;
int main()
{
int i,j,n,k,t,x=0,ans=0;
cin>>n>>k;
for (i=0;i<n;i++)
{
cin>>t;
book[t]++;
mp[t]++;
}
if (k==0)
{
cout<<mp.size()<<endl;
return 0;
}
else
{
for (i=0;i<k;i++)
{
x=0;
for (j=i;j<100005;j+=k)
a[x++]=book[j];
for (j=0;j<x;j++)
{
if (j==0)
dp[0]=a[0];
else if (j==1)
dp[1]=max(a[1],dp[0]);
else
dp[j]=max(dp[j-1],dp[j-2]+a[j]);
}
ans+=dp[x-1];
}
}
cout<<ans;
return 0;
}