CF582B 不下降子序列

1 CF582B 不下降子序列

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

给你一个长度为 \(n\times T\)的正整数数组 \(a_1, a_2, ..., a_{n \times T}\)。对于任意的 \(i>n\) 都保证 \(a_i = a_{i-n}\)。找出给定数组的最长不下降子序列。

数据范围:\(1 ≤ n ≤ 100, 1 ≤ T ≤ 10^7, 1 ≤ a_i ≤ 300\)

3 题解

考虑到 \(T \le 10^7\),我们不可能将整个序列还原出来再计算不下降子序列。我们观察到:只要 \(T > n\),那么最长不下降子序列中至少会出现 \(1\) 个重复的元素。因此,我们可以先枚举 \(n * n\) 个元素,找出它们的最长不下降子序列,再加上这 \(n\) 个数中出现最频繁的数与 \(T-n\) 的积。下面我简要说明一下以上做法的最优性和可行性。

最优性:首先,我们用 \(dp\) 求解的那一部分最长不下降子序列一定是最优的。至于在 \(T-n\) 中重复的部分,我们肯定希望重复时重复次数尽可能多,这样就可以使长度尽可能增加。此时,出现次数最频繁的数肯定重复次数最多,选择这个数肯定会使长度最长。

可行性:我们可以让最长不下降子序列中小于出现次数最频繁的数的那一部分放在开始,然后接着循环 \(T-n\) 次全部放上最频繁的数,最后再算上大于出现次数最频繁的数的那一部分最长不下降子序列。这样就可以构造出我们最终的最长不下降子序列。

4 代码(空格警告):

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 205;
const int M = 305;
#define int long long
int n, T, ans;
int a[N*N], dp[N*N], f[M], maxn, maxn2;
signed main()
{
    cin >> n >> T;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        f[a[i]]++;
        maxn = max(maxn, f[a[i]]);
    }
    for (int i = n+1; i <= n * min(n, T); i++) a[i] = a[i-n];
    for (int i = 1; i <= n * min(n, T); i++)
    {
        dp[i] = 1;
        for (int j = 1; j < i; j++)
        {
            if (a[i] >= a[j]) dp[i] = max(dp[i], dp[j]+1);
        }
        maxn2 = max(maxn2, dp[i]);
    }
    if (T < n)
    {
        cout << maxn2;
    }
    else cout << maxn2 + (T - n) * maxn;
    return 0;
}

欢迎关注微信公众号:智子笔记

posted @ 2021-03-04 21:46  David24  阅读(90)  评论(0编辑  收藏  举报