CF833B The Bakery
题目大意
将一个长度为 的序列分为 段,使得总价值最大。
一段区间的价值表示为区间内不同数字的个数。
题目分析
先不看数据范围,考虑朴素 :
令 表示前 个数被分成了 段的最大总价值,当前状态显然由分和不分区分开,即状态转移方程为 。
时间复杂度 ,显然 飞。
可以用线段树维护最大值,存储 ,然后依次考虑每个点的贡献,显然是对区间 做贡献 , 表示序列中上一个值为 的数的位置。至于为什么会对这段区间产生贡献,可以看出来如果一个值在区间中出现了很多次,那这些重复的数都不会产生贡献了。优化后时间复杂度为 。
代码
//2022/2/13
//2022/2/14
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <climits>//need "INT_MAX","INT_MIN"
#include <cstring>//need "memset"
#include <algorithm>
#define enter() putchar(10)
#define debug(c,que) cerr << #c << " = " << c << que
#define cek(c) puts(c)
#define blow(arr,st,ed,w) for(register int i = (st);i <= (ed); ++ i) cout << arr[i] << w;
#define speed_up() cin.tie(0),cout.tie(0)
#define endl "\n"
#define mst(a,k) memset(a,k,sizeof(a))
#define Abs(x) ((x) > 0 ? (x) : (-x))
#define GET(x) ((x) < 0 ? (x) + mod : (x))
#define MOD(x) \
((GET(x) >= mod) ? GET(x) - mod : GET(x))
namespace Newstd {
char buf[1 << 21],*p1 = buf,*p2 = buf;
inline int getc() {
return p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1 << 21,stdin),p1 == p2) ? EOF : *p1 ++;
}
inline int read() {
int ret = 0,f = 0;char ch = getc();
while (!isdigit(ch)) {
if(ch == '-') f = 1;
ch = getc();
}
while (isdigit(ch)) {
ret = (ret << 3) + (ret << 1) + ch - 48;
ch = getc();
}
return f ? -ret : ret;
}
inline void write(int x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace Newstd;
using namespace std;
const int ma1 = 3.5e4 + 5,ma2 = 55;
int a[ma1],pre[ma1],lst[ma1],dp[ma2][ma1];
//dp[i][j]:前 j 个数分成 i 段的最大价值和
int n,m;
struct Segment_Tree {
struct Node {
int l,r;
int tag,Max;
} node[ma1 << 2];
#define lson (p << 1)
#define rson (p << 1 | 1)
inline void pushup(int p) {
node[p].Max = max(node[lson].Max,node[rson].Max);
}
inline void build(int p,int l,int r,int k) {
node[p].l = l,node[p].r = r,node[p].tag = 0,node[p].Max = 0;
if (l == r) {
node[p].Max = dp[k][l];
return;
}
int mid = l + r >> 1;
build(lson,l,mid,k),build(rson,mid + 1,r,k);
pushup(p);
}
inline void pushdown(int p) {
if (node[p].tag) {
node[lson].tag += node[p].tag,node[rson].tag += node[p].tag;
node[lson].Max += node[p].tag,node[rson].Max += node[p].tag;
node[p].tag = 0;
}
}
inline void update(int x,int y,int p,int k) {
if (x <= node[p].l && node[p].r <= y) {
node[p].tag += k,node[p].Max += k;
return;
}
pushdown(p);
int mid = node[p].l + node[p].r >> 1;
if (x <= mid) update(x,y,lson,k);
if (y > mid) update(x,y,rson,k);
pushup(p);
}
inline int query(int x,int y,int p) {
if (x <= node[p].l && node[p].r <= y) {
return node[p].Max;
}
pushdown(p);
int mid = node[p].l + node[p].r >> 1,res = 0;
if (x <= mid) res = max(res,query(x,y,lson));
if (y > mid) res = max(res,query(x,y,rson));
return res;
}
#undef lson
#undef rson
} seg;
int main(void) {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
n = read(),m = read();
for (register int i = 1;i <= n; ++ i) a[i] = read();
for (register int i = 1;i <= n; ++ i) {
lst[i] = pre[a[i]];
pre[a[i]] = i;
}
for (register int i = 1;i <= m; ++ i) {
seg.build(1,0,n - 1,i - 1);
for (register int j = 1;j <= n; ++ j) {
seg.update(lst[j] + 1,j,1,1);
dp[i][j] = seg.query(1,j,1);
}
}
printf("%d\n",dp[m][n]);
return 0;
}
本文作者:Coros_Trusds
本文链接:https://www.cnblogs.com/Coros-Trusds/p/15894491.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步