历届试题 对局匹配

文章目录


提交此题 评测记录

资源限制

时间限制: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

思路:

蓝桥杯还真一题变一个算法啊,开始用dfs()深搜,只能过一个测试,后面就算不出来了。又补了dp算法,看了好几篇文章才写出来了。

  • 首先,进行分组,从0-(K-1) 之间的每一个分值各分成一组(score%k),例如:

    0, K, 2K, 3K, … ,nK; 1, 1+K, 1+2K, 1+3K, … ,1+nK; 2, 2+K, 2+2K, 2+3K, … ,2+nK;

    这样有两个特点:

  1. 组与组之间的分数肯定不能匹配
  2. 组内相邻分数可以匹配,相间分数不可匹配
  • 然后,对每一组用dp来求最大人数。对于前 j 个分数,可以拆分为是否加入第 j 个分数?
  1. 是。 most_p = most_p[n-2] + val[j] 前 j 个分数最大人数 = 前 j-2 个分数最大人数 + 第 j 个分数的人数

  2. 否。 most_p = most_p[n-1] 前 j 个分数最大人数 = 前 j-1 个分数最大人数

    由此得dp状态转移方程:
    d p [ i ] = m a x ( d p [ i − 2 ] + v a l [ i ] , d p [ i − 1 ] ) dp[i]=max(dp[i−2]+val[i],dp[i−1]) dp[i]=max(dp[i2]+val[i],dp[i1])

代码:

#include <iostream>
#include <vector>
using namespace std;

typedef long long ll;
const int maxp = 100005;
int score[maxp], N, K, max_score = -0x3f3f3f3f, temp, ans = 0, val[maxp], most_p[maxp];
vector<int> VS;

void dp()
{
    //K==0不能分组需要单独列出
    if (K == 0)
    {
        for (int i = 0; i <= max_score; i++)
            if (score[i])
                ans++;
    }

    //从0-(k-1)开始进行分组(是score%K的一系列值)。没必要用else,因为K=0进入不了分组循环
    for (int i = 0; i < K; i++)
    {
        int cnt = 0;
        // j,j+K,...,j+nK
        for (int j = i; j <= max_score; j += K)
            val[cnt++] = score[j];

        //边界,dp出口
        most_p[0] = val[0]; //前1个分数,没得选嘛
        most_p[1] = max(val[0], val[1]);  //前两个分数,选人数多的啦
        //进行dp,对于前j个分数来说,考虑第j个分数选不选:
        //1.选,那就是most_p[j - 2] + val[j],因为第j-1个分数不能选  
        //2.不选,那就和most_p[j - 1]一样
        //所以,只需要取两种情况中最多的人数就可以啦
        for (int j = 2; j < cnt; j++)
            most_p[j] = max(most_p[j - 1], most_p[j - 2] + val[j]);

        ans += most_p[--cnt];
    }
}

int main()
{
    cin >> N >> K;
    while (N--)
    {
        cin >> temp;
        score[temp]++;
        max_score = max_score > temp ? max_score : temp;
    }

    dp();
    cout << ans;
    return 0;
}

参考文章:

[蓝桥杯][2017年第八届真题]对局匹配 (C语言代码)-Dotcpp编程社区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值