CF833B The Bakery
题意
将长度为
朴素dp
记
dp时优化区间枚举有一个常用技巧:类似双指针地去不断扩展区间,避免多次计算同一个区间的贡献。
本题就是倒着枚举
int f[N][50], a[N], t[N];
int n, m;
int add(int x){
if(!t[x]) {
t[x] = 1;
return 1;
}
return 0;
}
signed main(){
n = rd(), m = rd() - 1;
F(i, 1, n) a[i] = rd();
F(j, 0, m){
F(i, 1, n){
F(i, 1, n) t[i] = 0;
int val = add(a[i]);
G(k, i - 1, 0){
if(j) f[i][j] = max(f[k][j - 1] + val, f[i][j]);
else f[i][j] = val;
if(k) val += add(a[k]);
}
}
}
printf("%d", f[n][m]);
return fflush(0), fclose(stdin), fclose(stdout), 0;
}
线段树优化
固定
发现较难处理的是
记
若
若
如上,在线段树上区间加,区间查就可以了。
时间复杂度
(所以单独写了个单点加,为什么更慢?)
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
using namespace std;
using ll = long long;
char buf[100], *p1 = buf, *p2 = buf;
inline int gc(){ return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++; }
inline int rd(){
int x = 0; char ch;
while(!isdigit(ch = gc()));
do x = (x << 3) + (x << 1) + (ch ^ 48); while(isdigit(ch = gc()));
return x;
}
const int N = 35500;
int pre[N], nw[N], a[N], f[N][50];
int n, m;
struct Segtree{
int mx[N << 2], tag[N << 2];
void pushup(int u){
mx[u] = max(mx[u * 2], mx[u * 2 + 1]);
}
void push(int u, int v){
mx[u] += v;
tag[u] += v;
}
void pushdown(int u){
if(tag[u]){
push(u * 2, tag[u]);
push(u * 2 + 1, tag[u]);
tag[u] = 0;
}
}
void update(int u,int l, int r, int x, int y, int v){
if(l >= x && r <= y){
push(u, v);
return ;
} pushdown(u);
int mid = (l + r) >> 1;
if(x <= mid) update(u * 2, l, mid, x, y, v);
if(y > mid) update(u * 2 + 1, mid + 1, r, x, y, v);
pushup(u);
}
void change(int u, int l, int r, int x, int v){
if(l == r){
mx[u] += v;
return ;
} pushdown(u);
int mid = (l + r) >> 1;
if(x <= mid) change(u * 2, l, mid, x, v);
else change(u * 2 + 1, mid + 1, r, x, v);
pushup(u);
}
int query(int u, int l, int r, int x, int y){
if(l >= x && r <= y) return mx[u];
pushdown(u);
int mid = (l + r) >> 1, ret = 0;
if(x <= mid) ret = max(ret, query(u * 2, l, mid, x, y));
if(y > mid) ret = max(ret, query(u * 2 + 1, mid + 1, r, x, y));
return ret;
}
}tr[50];
signed main(){
n = rd(), m = rd() - 1;
F(i, 1, n) a[i] = rd();
F(i, 1, n){
pre[a[i]] = nw[a[i]], nw[a[i]] = i;
F(j, 0, min(m, i - 1)) tr[j].update(1, 0, n, pre[a[i]], i - 1, 1);
F(j, 0, min(m, i - 1)){
if(!j){
f[i][j] = f[i - 1][j] + (!pre[a[i]]); // a[i] 第一次出现, 则有贡献
}
else{
f[i][j] = tr[j - 1].query(1, 0, n, j - 1, i - 1);
}
tr[j].change(1, 0, n, i, f[i][j]);
}
}
printf("%d", f[n][m]);
return fflush(0), fclose(stdin), fclose(stdout), 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2023-10-31 题解:洛谷P3745 期末考试(整数三分)
2023-10-31 线段树专题