CF833B 题解

原题传送门#

题意:将一个长度为 n 的序列划分成连续的 k 段,每一段的价值为段内不同的数字的数量,求最大价值。(n35000,k50)

划分问题,可以考虑 dp 。设 dpi,j 为将前 i 个数划分成 j 段可得到的最大价值,wl,r为区间[l,r]的价值。方程很容易写出来。

dpi,j=maxk=1i1dpk,j1+wk+1,i

暴力转移的时间复杂度为O(n2k),显然寄掉,考虑优化:

首先此题的要点显然就在于题目中价值的定义。显然它满足区间包含单调性,然后再简单的手玩一下可以发现它也满足四边形不等式(如果我没出错的话应该是四边形恒等式,但是反正不影响就是了)

既然 w 满足四边形不等式区间包含单调性,那么dp当然就满足四边形不等式。进一步说明,dp具有决策单调性。此题的重头戏就在这里。

那就直接二分呗,用分治就好了,至于为什么,我觉得就是个经典Trick,甚至好像不太像是Trick?,总之学了就知道了,详见OI Wiki

分治的过程比较板,不多说了,然后再来考虑如何计算 w ,显然双指针就好了,就和莫队里面的一样。

然后就结束了。时间复杂度:O(knlogn)

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define re register
const int N=35100,K=60;
int n,k,a[N],res,cnt[N],dp[N][K],L,R;
il void init(){
	for(re int i=0;i<=n;i++)for(re int j=0;j<=k;j++)dp[i][j]=-1;
	dp[0][0]=0;
}
il void add(int x){
	if(!cnt[x])res++;
	cnt[x]++;
}
il void del(int x){
	cnt[x]--;
	if(!cnt[x])res--;
}
il int query(int l,int r){
	while(L>l)add(a[--L]);
	while(R<r)add(a[++R]);
	while(L<l)del(a[L++]);
	while(R>r)del(a[R--]);
	return res;
}
il void solve(int l,int r,int optl,int optr,int id){
	if(l>r)return;
	int mid=(l+r)>>1,opt;
	for(re int i=optl;i<=min(mid,optr);i++){
		int tmp=dp[i-1][id-1]+query(i,mid);
		if(tmp>dp[mid][id])dp[mid][id]=tmp,opt=i;
	}
	solve(l,mid-1,optl,opt,id);
	solve(mid+1,r,opt,optr,id);
}
il int read(){
    re int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
int main(){
	n=read(),k=read();
	for(re int i=1;i<=n;i++)a[i]=read();
	init();
	for(re int i=1;i<=k;i++)solve(1,n,1,n,i);
	cout<<dp[n][k];
    return 0;
}
posted @   MrcFrst  阅读(36)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示
主题色彩