问题描述
小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是 K 的两名用户匹配在一起。
如果两人分差小于或大于 K,系统都不会将他们匹配。
现在小明知道这个网站总共有 N 名用户,以及他们的积分分别是 A1, A2, … AN。
小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来 (任意两名用户积分差不等于 K)?
输入格式
第一行包含两个个整数 N 和 K。
第二行包含N个整数 A1, A2, … AN。
输出格式
一个整数,代表答案。
样例输入1
10 0
1 4 2 8 5 7 1 4 2 8
样例输出1
6
样例输入2
10 1
2 1 1 1 1 4 4 3 4 4
样例输出2
8
数据范围
对于 30% 的数据,1 ≤ N ≤ 10
对于 100% 的数据,1 ≤ N ≤ 105, 0 ≤ Ai ≤ 105, 0 ≤ K ≤ 105
题解一
DFS(会超时):蓝桥杯官网只过了一个数据,其它的都超时了😂
#include <iostream>
using namespace std;
int n, k, ans;
bool st[100010];
int s[100010], a[100010];
bool judge(int u, int i)
{
for (int j = 1; j < u; j ++)
if(a[j] - s[i] == k || s[i] - a[j] == k) return false;
return true;
}
void dfs(int u)
{
ans = max(ans, u - 1);
for (int i = 1; i <= n; i ++)
{
if(st[i] || !judge(u, i)) continue;
st[i] = true;
a[u] = s[i];
dfs(u + 1);
st[i] = false;
}
return;
}
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++) cin >> s[i];
dfs(1);
cout << ans << endl;
return 0;
}
ps:然而在dotcpp上能通过全部的数据🤣
题解二
动态规划:
以第二个数据 2 1 1 1 1 4 4 3 4 4
为例,由于 k = 1,所以分成 1 组公差为 1 等差数列。
等差数列
:0 1 2 3 4 …出现次数
:0 4 1 1 4 …
决策
:由于相邻两项公差为 k,所以不能选择相邻的两项。
状态转移方程:
当 i == 0
,f[i] = s[i]
当 i == 1
,f[i] = max(f[i - 1], s[i])
当 i >= 2
,f[i] = max(f[i - 1], f[i - 2] + s[i])
#include <iostream>
using namespace std;
const int N = 100010;
int n, k, x, ans;
int cnt[N], s[N], f[N];
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++)
{
cin >> x;
cnt[x] ++; // 统计每个积分出现的次数
}
if(k == 0) // k = 0 需要特判
{
for (int i = 0; i < N; i ++)
if(cnt[i]) ans ++;
}
else
{
for (int i = 0; i < k; i ++) // 分成 k 个公差为 k 的等差数列
{
int u = 0;
for (int j = i; j <= N; j += k) // 首项分别为 i 出现的次数
s[u ++] = cnt[j];
f[0] = s[0];
for (int j = 1; j < u; j ++)
{
if(j == 1) f[j] = max(f[j - 1], s[j]);
else f[j] = max(f[j - 1], f[j - 2] + s[j]);
}
ans += f[u - 1]; // 加上每组等差数列选择的最大值
}
}
cout << ans << endl;
return 0;
}