YACS 2023年1月月赛 甲组 T2 分割数列(二) 题解

题目链接

继上个月的分割数列(一)又出了这道题。

首先还是考虑 n2DP ,设 f[i] 为分到 i 个的最小权重之和。

转移枚举上一个在哪里分就行了。

显然时间会超限,我们考虑一下优化:

首先,如果有连续的数字相同,那么就把他们放到一个块里。

处理完后还是 n2DP,这样时间复杂度就减少到了 O(块数2)

接着我们再来考虑剪枝,显然把前面每一个块划分成一个数列是比较优秀的。

他的代价为前面块的数量,所以我们转移的时候,当前的 f[i] 已经超过了块数

那就没必要继续下去了,直接 break 掉,平均时间复杂度 O(nn)

不过比如一些毒瘤数据:两个数交替出现。就会卡成 O(n2),所以可以再加一个 set 优化。

那样时间复杂度就成了铁 O(nn×logn) 就很难过,所以我就这样吧。

T3 还是状压改天在写。

贴代码:

复制代码
#include <iostream>
#include <cstring>
#define int long long
using namespace std;
int n, cnt, cnt1, tot;
int a[50005], f[50005], v[50005], tmp[50005], A[50005];
signed main() {
    scanf ("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf ("%d", &a[i]);
        if (a[i] != a[i - 1]) A[++ tot] = a[i];
    }
    f[0] = 0;
    for (int i = 1; i <= tot; i ++) {
        tmp[A[i] ] ++;
        if (tmp[A[i] ] == 1) cnt1 ++;
        f[i] = i;
        memset (v, 0, sizeof v);
        v[A[i]] = 1;
        int cnt = 1;
        for (int j = i; j >= 1; j --)
        {
            if (cnt * cnt > i) break;
            if (!v[A[j] ]) {
                cnt ++;
                v[A[j]] = 1;
            }     
            f[i] = min (f[i], f[j - 1] + cnt * cnt);
        }
    }
    printf ("%d", f[tot]);
}
复制代码

 

posted @   Xy_top  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示