版权声明:本文为博主原创文章,未经博主允许不得转载。
历届试题 对局匹配
时间限制:1.0s 内存限制:256.0MB
问题描述
小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是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
原文摘自蓝桥杯。
看到这数据就猜是dp了。
思路解析:
假设k=1;
对于num[0],num[1],有两种情况,第一 选num[0],不选num[1]。即dp[0][0]=num[0],dp[1][0]=0,第二选num[1],不选num[0]。dp[0][1]=0,dp[1][1]=num[1]。
则对于num[2]选还是不选就由前面num[0],num[1]决定。
即dp[2][0]=max(dp[1][0],dp[0][0]+num[2]]),dp[2][1]=max(dp[1][1],dp[0][1]+num[2]);
同理可以得出k!=0的所有状态转移方程dp[i][0]=max(dp[i-k][0],dp[i-2k][0]+num[i]]),dp[i][1]=max(dp[i-k][1],dp[i-2k][1]+num[i]);其中(i>=k*2)
假设x为初始的起点;
因为对于0<=x<k,x对应不同的初始值直接是不会互相影响的
令ans[i%m]=max(dp[i][0],dp[i][1]);可以得出不同初始值所对应的最大可选数量。
则答案res就是ans[0]+ans[1]+…+ans[k-1];
由于这种dp的状态转移方程只适用k!=0,因此对于k==0得特殊判断
复杂度O(n)。
#include<iostream>
using namespace std;
int num[100005],ans[100005];
int dp[100005][2];
int get_Max(int a,int b)求最大值
{
if(a>b)
return a;
return b;
}
int main()
{
int i,j,n,m;
int res=0;
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
{
int x;
scanf("%d",&x);
if(m==0)
{
if(!num[x])
{
res++;
}else
{
continue;
}
}
num[x]++;
}
if(m==0)
{
printf("%d\n",res);
return 0;
}
for(i=0;i<m;i++)//第一种情况
{
dp[i][0]=num[i];
ans[i]=get_Max(num[i],ans[i]);
}
for(i=m;i<m*2;i++)//第二种情况
{
dp[i][1]=num[i];
ans[i%m]=get_Max(num[i],ans[i%m]);
}
for(i=m*2;i<=100000;i++)
{
dp[i][0]=get_Max(dp[i-m*2][0]+num[i],dp[i-m][0]);//状态转移方程
dp[i][1]=get_Max(dp[i-m*2][1]+num[i],dp[i-m][1]);
ans[i%m]=get_Max(dp[i][1],ans[i%m]);//保存过程中不同初始值最大可选人数
ans[i%m]=get_Max(dp[i][0],ans[i%m]);
}
for(i=0;i<m;i++)//求结果
{
res+=ans[i];
}
printf("%d\n",res);
return 0;
}//代码仅是草创,仅与借鉴
博主第一处写博客,若有瑕疵,愿请谅解。