老夫聊发少年狂,碱金属,丢池塘。浮溶游响,激起千朵浪。氢锂钠|

Yaosicheng124

园龄:1年3个月粉丝:8关注:11

CF 1527 E

题目描述

我们定义一个数组 P 的代价为:

xPlast(x)first(x)

这里 first(x),last(x) 是指 x 第一次,最后一次出现的位置。

你需要将数组 A 分成恰好 k 段,求最小总代价。

思路

dpi,j 表示已经分了 i 段,末尾在 j​ 的最小代价。

由于代价是最后一个减前一个,可以看作是 i2i1+i3i2+,这里 ij 表示第 jx 的下标。

所以转移可以这样来实现:当枚举到 i 时,之后 ab(1a<last,ibN) 的转移一定会多 ilast 的代价。这个可以用线段树维护区间最小值。

每次做完一轮 dp 就把 dp 值丢进线段树即可。

空间复杂度 O(N),时间复杂度 O(NKlogN)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 35005;

struct Segment_Tree {
  int l[MAXN << 2], r[MAXN << 2], Min[MAXN << 2], lazy[MAXN << 2];
  void build(int u, int s, int t) {
    l[u] = s, r[u] = t, lazy[u] = 0;
    if(s == t) {
      Min[u] = 0;
      return;
    }
    int mid = (s + t) >> 1;
    build(u << 1, s, mid), build((u << 1) | 1, mid + 1, t);
    Min[u] = min(Min[u << 1], Min[(u << 1) | 1]);
  }
  void tag(int u, int x) {
    Min[u] += x, lazy[u] += x;
  }
  void pushdown(int u) {
    tag(u << 1, lazy[u]), tag((u << 1) | 1, lazy[u]), lazy[u] = 0;
  }
  void update(int u, int s, int t, int x) {
    if(s > t) {
      return;
    }
    if(l[u] >= s && r[u] <= t) {
      tag(u, x);
      return;
    }
    pushdown(u);
    if(s <= r[u << 1]) {
      update(u << 1, s, t, x);
    }
    if(t >= l[(u << 1) | 1]) {
      update((u << 1) | 1, s, t, x);
    }
    Min[u] = min(Min[u << 1], Min[(u << 1) | 1]);
  }
  int Getmin(int u, int s, int t) {
    if(s > t) {
      return 0;
    }
    if(l[u] >= s && r[u] <= t) {
      return Min[u];
    }
    pushdown(u);
    int x = int(2e9);
    if(s <= r[u << 1]) {
      x = min(x, Getmin(u << 1, s, t));
    }
    if(t >= l[(u << 1) | 1]) {
      x = min(x, Getmin((u << 1) | 1, s, t));
    }
    return x;
  }
}tr;

int n, k, a[MAXN], last[MAXN], dp[MAXN];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> k;
  for(int i = 2; i <= n + 1; ++i) {
    cin >> a[i];
  }
  tr.build(1, 1, n + 1);
  tr.update(1, 2, n + 1, int(2e9));
  for(int i = 1; i <= k; ++i) {
    for(int j = 1; j <= n; ++j) {
      last[j] = 1;
    }
    for(int j = 2; j <= n + 1; ++j) {
      tr.update(1, 1, last[a[j]] - 1, j - last[a[j]]);
      last[a[j]] = j;
      dp[j] = tr.Getmin(1, 1, j - 1);
    }
    tr.build(1, 1, n + 1);
    tr.update(1, 1, 1, int(2e9));
    for(int j = 2; j <= n + 1; ++j) {
      tr.update(1, j, j, dp[j]);
    }
  }
  cout << dp[n + 1];
  return 0;
}

本文作者:Yaosicheng124

本文链接:https://www.cnblogs.com/yaosicheng124/p/18417386

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Yaosicheng124  阅读(4)  评论(0编辑  收藏  举报
  1. 1 Minecraft C418
Minecraft - C418
00:00 / 00:00
An audio error has occurred.

暂无歌词

加载中…

{{tag.name}}

{{tran.text}}{{tran.sub}}
无对应文字
有可能是
{{input}}
尚未录入,我来提交对应文字
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示