对局匹配[dp]
time limit per test | memory limit per test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
Description:
小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K,系统都不会将他们匹配。
现在小明知道这个网站总共有N名用户,以及他们的积分分别是A1, A2, … AN。
小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来(任意两名用户积分差不等于K)?
Input
第一行包含两个个整数N和K。
第二行包含N个整数A1, A2, … AN。
对于30%的数据,1 <= N <= 10
对于100%的数据,1 <= N <= 100000, 0 <= Ai <= 100000, 0 <= K <= 100000
Output
一个整数,代表答案。
Example input
10 0
1 4 2 8 5 7 1 4 2 8
Example output
6
分析:
题意:
其实,一开始一直看不懂样例到底怎么整的
(于是开始借用万能的度娘, 我也忘记是看哪个博客突然间就理解了的
就是说,可以选择每个人上线或者不上线,使得
a
b
s
(
a
−
b
)
≠
k
abs(a-b) ≠ k
abs(a−b)=k的个数尽量大
问最多可以多少人满足上诉条件
分析:
对于每个当前值
x
x
x, 不满足上述条件的情况只有
(
x
+
k
)
&
&
(
x
−
k
)
(x + k) \&\& (x - k)
(x+k)&&(x−k)
那么可以考虑,对于每个
x
(
0
≤
x
<
k
)
x(0 \leq x < k)
x(0≤x<k),有
x
+
k
,
x
+
2
k
,
x
+
3
k
,
.
.
.
,
x
+
j
k
x + k, x + 2k, x + 3k, ..., x + jk
x+k,x+2k,x+3k,...,x+jk当做是同一组
不满足条件的情况只有在同一组的
(
x
+
k
)
&
&
(
x
−
k
)
(x+k) \&\& (x-k)
(x+k)&&(x−k)的情况
遍历每一组的初始值
x
(
0
≤
x
<
k
)
x(0 \leq x < k)
x(0≤x<k)
当前组可以满足条件的个数即为
(由于当前组,
c
n
t
[
j
]
cnt[j]
cnt[j]表示改组第
j
j
j个数有几个,
d
p
[
j
]
dp[j]
dp[j]表示到第
j
j
j个最多可以同时在线几个)
d
p
[
j
]
=
m
a
x
(
d
p
[
j
−
1
]
,
d
p
[
j
−
2
]
+
v
i
s
[
j
]
)
,
1
<
j
dp[j] = max(dp[j-1], dp[j-2]+vis[j]), 1 < j
dp[j]=max(dp[j−1],dp[j−2]+vis[j]),1<j
其中
j
j
j表示的是同一组的第
j
j
j个数,由于从前往后推,
d
p
[
j
−
2
]
dp[j-2]
dp[j−2]是积分相差
k
k
k的位置的数
d
p
[
j
]
=
m
a
x
(
d
p
[
0
]
,
v
i
s
[
j
]
)
,
j
=
=
1
dp[j] = max(dp[0], vis[j]), j == 1
dp[j]=max(dp[0],vis[j]),j==1
由于上式必须要
2
≤
2
2 \leq 2
2≤2才可以,因此在
j
=
=
1
&
&
j
=
=
0
j == 1 \&\& j == 0
j==1&&j==0的时候要初始化
j
=
=
0
j == 0
j==0时初始化就是
c
n
t
[
0
]
cnt[0]
cnt[0]
Code:
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int cnt[maxn];
int vis[maxn];
int dp[maxn];
int main() {
int n, k, x, maxx = -1;
scanf("%d%d", &n, &k);
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; ++i) {
scanf("%d", &x); cnt[x]++;
maxx = max(maxx, x);
}
int m, res = 0;
if(k == 0) {
for(int i = 0; i <= maxx; ++i)
if(cnt[i]) res++;
printf("%d\n", res);
return 0;
}
memset(dp, 0, sizeof(dp));
for(int i = 0; i < k; ++i) { // 遍历组初值
m = 0;
for(int j = i; j <= maxx; j += k)
vis[m++] = cnt[j]; // 每组
dp[0] = vis[0];
for(int j = 0; j < m; ++j) {
if(j == 1) dp[j] = max(dp[0], vis[j]);
else dp[j] = max(dp[j-1], dp[j-2] + vis[j]);
}
res += dp[m - 1];
}
printf("%d\n", res);
return 0;
}