2358: LLM找对象【dp+离散化】

题目描述
找对象可不是一件容易的事情,如果你想找个好对象啊,喜欢打游戏的得把游戏戒了,喜欢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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值