Codeforces 834D The Bakery【dp+线段树维护+lazy】

简介: D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard input output:standard output ...

D. The Bakery

time limit per test:2.5 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredients and a wonder-oven which can bake several types of cakes, and opened the bakery.

Soon the expenses started to overcome the income, so Slastyona decided to study the sweets market. She learned it's profitable to pack cakes in boxes, and that the more distinct cake types a box contains (let's denote this number as the value of the box), the higher price it has.

She needs to change the production technology! The problem is that the oven chooses the cake types on its own and Slastyona can't affect it. However, she knows the types and order of n cakes the oven is going to bake today. Slastyona has to pack exactly k boxes with cakes today, and she has to put in each box several (at least one) cakes the oven produced one right after another (in other words, she has to put in a box a continuous segment of cakes).

Slastyona wants to maximize the total value of all boxes with cakes. Help her determine this maximum possible total value.

Input

The first line contains two integers n and k (1 ≤ n ≤ 35000, 1 ≤ k ≤ min(n, 50)) – the number of cakes and the number of boxes, respectively.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n) – the types of cakes in the order the oven bakes them.

Output

Print the only integer – the maximum total value of all boxes with cakes.

Examples
Input
4 1
1 2 2 1
Output
2
Input
7 2
1 3 3 1 4 4 4
Output
5
Input
8 3
7 7 8 7 7 8 1 7
Output
6
Note

In the first example Slastyona has only one box. She has to put all cakes in it, so that there are two types of cakes in the box, so the value is equal to 2.

In the second example it is profitable to put the first two cakes in the first box, and all the rest in the second. There are two distinct types in the first box, and three in the second box then, so the total value is 5.

题目链接:http://codeforces.com/contest/834/problem/D

题意:把n个数分成k段,每段的价值等于这一段内不同数字的个数,求总的最大价值。

可以很快发现这是一个dp,dp[i][j]表示到第i个数字,已经分成了k段的最大价值。

dp[i][j] = max(dp[t][j-1]) (1<= t < i)

可以发现转移不是那么容易,所以我们用到线段树去维护当前位置前面的最大价值。

对于状态i,j,线段树维护的是1~i-1的最大值

对于每一个位置,找到前面最后一个与它数字相同的的位置,把这之间线段树的值都加上1,然后dp[i][j]的值就是j-1到i-1的最大值。

最后答案就是dp[n][k]。

(注意线段树的区间范围是0~n,因为可以直接从0转移过来

下面给出AC代码:【二维数组改写成一维数组(个人原因,不太喜欢高维度的)】

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 35010
 4 #define INF 0x3f3f3f3f
 5 int addv[maxn*4],Max[maxn*4];
 6 int dp[maxn],ql,qr;
 7 int pre[maxn], last[maxn], a[maxn];
 8 void build(int l,int r,int o)
 9 {
10     addv[o]=0;
11     if(l == r)
12     {
13         Max[o]=dp[l];
14         return;
15     }
16     int mid=l+(r-l)/2;
17     build(l,mid,o*2);
18     build(mid+1,r,o*2+1);
19     Max[o]=max(Max[o*2],Max[o*2+1]);
20 }
21 void pushdown(int o)
22 {
23     int lc=o*2,rc=o*2+1;
24     if(addv[o])
25     {
26         addv[lc]+=addv[o];
27         addv[rc]+=addv[o];
28         Max[lc]+=addv[o];
29         Max[rc]+=addv[o];
30         addv[o]=0;
31     }
32 }
33 void update(int l,int r,int o)
34 {
35     if(ql>qr)
36         return;
37     if(ql<=l&&qr>=r)
38     {
39         addv[o]++;
40         Max[o]++;
41         return;
42     }
43     pushdown(o);
44     int mid=l+(r-l)/2;
45     if(ql<=mid)
46        update(l,mid,o*2);
47     if(qr>mid)
48        update(mid+1,r,o*2+1);
49     Max[o]=max(Max[o*2],Max[o*2+1]);
50 }
51 int query(int l,int r,int o)
52 {
53     if(ql<=l&&qr>=r)
54     {
55         return Max[o];
56     }
57     pushdown(o);
58     int mid=l+(r-l)/2;
59     int best=-INF;
60     if(ql<=mid)
61        best=max(best,query(l,mid,o*2));
62     if(qr>mid)
63        best=max(best,query(mid+1,r,o*2+1));
64     return best;
65 }
66 int main()
67 {
68     int n,k;
69     scanf("%d%d",&n,&k);
70     memset(last,-1,sizeof(last));
71     int cnt=0;
72     for(int i=1;i<=n;i++)
73     {
74         scanf("%d",&a[i]);
75         pre[i]=last[a[i]];
76         last[a[i]]=i;
77         if(pre[i]==-1)
78            cnt++;
79         dp[i]=cnt;
80     }
81     for(int kk=2;kk<=k;kk++)
82     {
83         for(int i=1;i<kk-1;i++)
84             dp[i]=-INF;
85         build(1,n,1);
86         for(int i=kk;i<=n;i++)
87         {
88             ql=max(1,pre[i]),qr=i-1;
89             update(1,n,1);
90             ql=1,qr=i-1;
91             dp[i]=query(1,n,1);
92         }
93     }
94     printf("%d\n",dp[n]);
95     return 0;
96 }

 官方题解:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <map>
 4 
 5 #define K first
 6 #define V second
 7 
 8 const int N = 35001;
 9 
10 int last[N], pre[N], dp[N];
11 
12 int main()
13 {
14     int n, m;
15     while (scanf("%d%d", &n, &m) == 2) {
16         memset(last, 0, sizeof(last));
17         for (int i = 1, a; i <= n; ++ i) {
18             scanf("%d", &a);
19             pre[i] = last[a];
20             last[a] = i;
21         }
22         dp[0] = 0;
23         for (int i = 1; i <= n; ++ i) {
24             dp[i] = dp[i - 1] + !pre[i];
25         }
26         for (int k = 2; k <= m; ++ k) {
27             std::map<int, int> c;
28             c[0] = n + 1;
29             int last_dp = dp[k - 1];
30             for (int i = k; i <= n; ++ i) {
31                 int now = 0;
32                 while (now + c.rbegin()->V <= last_dp) {
33                     now += c.rbegin()->V;
34                     c.erase(c.rbegin()->K);
35                 }
36                 c.rbegin()->V += now - last_dp;
37                 c[i] = last_dp + 1;
38                 auto it = c.upper_bound(pre[i]);
39                 it --;
40                 it->V --;
41                 if (it->V == 0) {
42                     c.erase(it->K);
43                 }
44                 last_dp = dp[i];
45                 dp[i] = (n + 1) - c.begin()->V;
46             }
47         }
48         printf("%d\n", dp[n]);
49     }
50 }

 

 

 

目录
相关文章
|
13天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
12天前
|
存储 人工智能 搜索推荐
终身学习型智能体
当前人工智能前沿研究的一个重要方向:构建能够自主学习、调用工具、积累经验的小型智能体(Agent)。 我们可以称这种系统为“终身学习型智能体”或“自适应认知代理”。它的设计理念就是: 不靠庞大的内置知识取胜,而是依靠高效的推理能力 + 动态获取知识的能力 + 经验积累机制。
393 135
|
12天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
496 132
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
2天前
|
人工智能 移动开发 自然语言处理
阿里云百炼产品月刊【2025年9月】
本月通义千问模型大升级,新增多模态、语音、视频生成等高性能模型,支持图文理解、端到端视频生成。官网改版上线全新体验中心,推出高代码应用与智能体多模态知识融合,RAG能力增强,助力企业高效部署AI应用。
207 0
|
12天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
502 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
6天前
|
存储 JSON 安全
加密和解密函数的具体实现代码
加密和解密函数的具体实现代码
235 136
|
23天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1585 87