在保持顺序的情况下,求摆放的最大美学值
正常做法来说是dp,设dp[i][j]表示第i束花放不放在第j个花盆里的最大值,转移方程就应该是:
不放:dp[i][j]=dp[i][j−1]
放:dp[i][j]=dp[i−1][j−1]+a[i]
但是当时突发奇想,想了个线段树,没想到写过了,故来记录线段树做法,那么为什么可以用线段树做呢,可以发现, 下一层更新答案要在上一层的基础上再往下更新,第i束花最前可以放在第i个花盆(题意),那么f[i][j]表示第i束花放在第j个花盆的最大值,那么他一定是由max(f[i−1][i−1...j−1])更新来的,看到这个方程第一眼想到了单调队列去维护,但发现这个长度不是固定的,所以不能用这个来维护,那么还能动态维护区间最大值的方式就想到了线段树。把原来线段树维护的sum改成维护max可行,因为每一层都只跟上一层有关,所以线段树只需要维护上一层的信息就可以,而又因为f[i][]只跟f[i−1][]有关,故线段树相当于那个压成一维的滚动数组,更新就要倒着更新。dp是O(nm)的复杂度,线段树维护只多了一个log(m),故是O(nmlogm)的复杂度,可以过全部数据
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 105,inf = 2147483647;
int n,m,f[maxn][maxn],a[maxn][maxn],res,pos,pre[maxn][maxn],ans[maxn];
struct Tree{
int l,r,k,maxi,pos;
}tree[maxn<<2];
void build(int l,int r,int k)
{
tree[k] = (Tree){l,r,k,0};
if(l == r)
{
tree[k].maxi = a[1][l];
tree[k].pos = l;
return ;
}
int mid = l + r >> 1;
build(l,mid,k<<1);
build(mid+1,r,(k<<1)+1);
if(tree[k<<1].maxi >= tree[(k<<1)+1].maxi)
{
tree[k].maxi = tree[k<<1].maxi;
tree[k].pos = tree[k<<1].pos;
}
else{
tree[k].maxi = tree[(k<<1)+1].maxi;
tree[k].pos = tree[(k<<1)+1].pos;
}
return ;
}
void update(int p,int v,int k)
{
if(tree[k].l == tree[k].r)
{
tree[k].maxi = v;
return ;
}
int mid = tree[k].l + tree[k].r >> 1;
if(p <= mid)
update(p,v,k<<1);
else update(p,v,(k<<1)+1);
if(tree[k<<1].maxi >= tree[(k<<1)+1].maxi)
{
tree[k].maxi = tree[k<<1].maxi;
tree[k].pos = tree[k<<1].pos;
}
else{
tree[k].maxi = tree[(k<<1)+1].maxi;
tree[k].pos = tree[(k<<1)+1].pos;
}
return ;
}
void query(int l,int r,int k)
{
if(tree[k].l >= l && tree[k].r <= r)
{
if(tree[k].maxi >= res)
{
res = tree[k].maxi;
pos = tree[k].pos;
}
return ;
}
int mid = (tree[k].l + tree[k].r) >> 1;
if(l <= mid)
query(l,r,k<<1);
if(r > mid)
query(l,r,(k<<1)+1);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
build(1,m,1);
for(int i=2;i<=n;i++)
{
for(int j=m;j>=1;j--)
{
if(j >= i)
{
res = -inf;
query(i-1,j-1,1);
f[i][j] = res + a[i][j];
pre[i][j] = pos;
update(j,f[i][j],1);
}
else update(j,-inf,1);
}
}
printf("%d\n",tree[1].maxi);
int k = n,mpos = tree[1].pos,cnt = 0;
ans[++cnt] = mpos;
while(pre[k][mpos])
{
ans[++cnt] = pre[k][mpos];
mpos = pre[k][mpos];
k --;
}
for(int i=cnt;i>=1;i--)
printf("%d ",ans[i]);
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2019-04-11 [BSGS]