CF833B The Bakery

洛谷题面

题目大意

将一个长度为 n 的序列分为 m 段,使得总价值最大。

一段区间的价值表示为区间内不同数字的个数。

题目分析

先不看数据范围,考虑朴素 dp

dp[i][j] 表示前 j 个数被分成了 i 段的最大总价值,当前状态显然由分和不分区分开,即状态转移方程为 dp[i][j]=max{dp[i1][k]+val(k+1,j)}(1k<j)

时间复杂度 O(n3k),显然 T 飞。

可以用线段树维护最大值,存储 dp[i1][j],然后依次考虑每个点的贡献,显然是对区间 [last[i]+1,i] 做贡献 1last[i] 表示序列中上一个值为 a[i] 的数的位置。至于为什么会对这段区间产生贡献,可以看出来如果一个值在区间中出现了很多次,那这些重复的数都不会产生贡献了。优化后时间复杂度为 O(nklogn)

代码

//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 中国大陆许可协议进行许可。

posted @   Coros_Trusds  阅读(63)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.