题目描述
找对象可不是一件容易的事情,如果你想找个好对象啊,喜欢打游戏的得把游戏戒了,喜欢acm的得把acm戒了,然后“天将降女朋友于斯人也,必先看其有没有穿拖鞋”,现在LLM相中了N个妹子,他通过观星、占卜、杀队友祭天等方法终于发现了自己与这N个妹子分别
相遇的时间,但是LLM还是想穿拖鞋(但是穿了拖鞋就会情商急速下降找无法认识妹子),因此LLM决定忍痛割爱选择K天不穿拖鞋,但是不可以有任意两天连续不穿拖鞋,现在LLM问你他最多可以认识多少妹子
输入
每个测试文件包含不多于10组测试样例
每个测试样例第一行包含两个整数,N,K
接下来一行有N个数字,分别代表和第i个妹子相遇的是哪一天(这一天的编号小于100000000)
1<=N<=500,1<=K<=100000000
输出
输出包含一行,代表可以认识的妹子数量
样例输入
5 2
666 233 10086 233 10086
样例输出
4
题目链接
思路:(标程)
最开始离散化想到了,但是dp方程没写出来,好气,菜哭!
离散化相遇日期编号示例如下:
对于:10 11 12 13 17 23
可以离散成:1 2 3 4 6 8 (a[i]表示第i天的妹子数量)
然后如果k大于n的话那么超出的部分没有意义,因此k实际有效值最大也就是最大天数u。
dp[i][j][0]代表第i天已经不穿拖鞋j天了,本天穿拖鞋了;
dp[i][j][1]代表第i天已经不穿拖鞋j天了,本天没穿拖鞋;
状态转移方程看代码(注意初始化)
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;
int c[1010], dp[1010][1010][2], a[1010];
int main() {
int n, k;
while(scanf("%d %d", &n, &k) != EOF) {
memset(c, 0, sizeof(c));
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
}
sort(c + 1, c + n + 1);
c[n + 1] = 1e8 + 10;
int ans = 0, u = 1, cnt = c[1];
for(int i = 1; i <= n + 1; i++) { //离散化
if(cnt == c[i]) {
ans++;
}
else {
if(cnt != c[i] - 1) {
a[u++] = ans;
u++;
}
else a[u++] = ans;
ans = 1;
cnt = c[i];
}
}
// for(int i = 1; i < u; i++) {
// printf("%d -> %d\n", i, a[i]);
// }
k = min(k, u);
int maxn = 0;
memset(dp, -1, sizeof(dp));
dp[1][0][0] = 0, dp[1][1][1] = a[1]; //初始值
for(int i = 1; i < u - 1; i++) {
for(int j = 0; j <= k; j++) {
if(dp[i][j][0] >= 0) { //状态转移方程
dp[i + 1][j + 1][1] = max(dp[i + 1][j + 1][1], dp[i][j][0] + a[i + 1]);
dp[i + 1][j][0] = max(dp[i + 1][j][0], dp[i][j][0]);
}
if(dp[i][j][1] >= 0) {
dp[i + 1][j][0] = max(dp[i + 1][j][0], dp[i][j][1]);
}
}
}
for(int j = 0; j <= k; j++) { //统计最大值
maxn = max(maxn, max(dp[u - 1][j][0], dp[u - 1][j][1]));
}
printf("%d\n", maxn);
}
return 0;
}