首页 > 其他分享 >CF1648D Serious Business题解

CF1648D Serious Business题解

时间:2024-09-29 15:01:52浏览次数:1  
标签:max le Business int 题解 sum li CF1648D dp

题目链接
关键:DP状态的设计
\(dp[i]\) 表示走到\((2,i)\)的最小价值。
转移分类讨论

  1. 只用一个区间\(i\)从\([li,x]\)选择位置向下拐
    \(dp[i]=max_{li\le k \le x}(sum[1][k]+sum[2][x]-sum[2][k-1]+v[i])\)
  2. 使用别的区间
    显然转移点小于\(li\),不然用一个区间即可。
    \(dp[i]=max_(dp[li-1]+sum[2][x]-sum[2][li-1]-v[i])\)

总结起来(i可能在很多个区间中):
\(dp[x]=max_{li\le x\le ri}(dp[li-1]+sum[2][x]-sum[2][li-1]-v[i],max_{li\le k\le x}(sum[1][k]+sum[2][x]-sum[2][k-1]-v[i]))\)
\(dp[x]=max_{li\le x\le ri}(dp[li-1]-sum[2][li-1]-v[i],max_{li\le k\le x}(sum[1][k]-sum[2][k-1]-v[i]))+sum[2][x]\)

实现:
直接实现显然超时,所以用数据结构优化转移。
前一半显然,可按\(li\)排序后加入线段树维护一下(我感觉拍完序可以直接做,有空来试一试再说)
后一半通过单独维护[l,r]区间可取的最小的vi,以及最大值和答案,因为从小开始加,所以x加入时,加入的li都比x小,线段树查的是大于等与当前位置的最大值,这样x一定在区间中,所以直接加入即可。

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define ll long long
const ll inf=1e18;
int n,q;
struct node
{
    int l,r,ct;
}qu[N];
ll a[4][N],sum[4][N],dp[N],d1[N<<2],d2[N<<2],lz[N<<2],K2[N<<2];
bool cmp(node x,node y)
{
    return x.l<y.l;
}
void pushdown(int i)
{
	if(lz[i]==-inf) return ;
	d2[i<<1]=max(d2[i<<1],lz[i]-K2[i<<1]);
	d2[i<<1|1]=max(d2[i<<1|1],lz[i]-K2[i<<1|1]);
	lz[i<<1]=max(lz[i<<1],lz[i]),lz[i<<1|1]=max(lz[i<<1|1],lz[i]);
	lz[i]=-inf;
    return ;
}
void insert1(int x,int l,int r,int zhi,ll z)
{
    if(l==r)
    {
        d1[x]=max(d1[x],z);
        return;
    }
    int mid=(l+r)>>1;
    if(zhi<=mid)insert1(x<<1,l,mid,zhi,z);
    else insert1(x<<1|1,mid+1,r,zhi,z);
    d1[x]=max(d1[x<<1],d1[x<<1|1]);
}
void insert2(int x,int l,int r,int zhi,ll z,int kk)
{
    if(l==r)
    {
        if(z>d2[x])d2[x]=z,K2[x]=kk;
        return;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if(zhi<=mid)insert2(x<<1,l,mid,zhi,z,kk);
    else insert2(x<<1|1,mid+1,r,zhi,z,kk);
    K2[x]=min(K2[x<<1],K2[x<<1|1]);
    d2[x]=max(d2[x<<1],d2[x<<1|1]);
}
ll query1(int x,int l,int r,int zhi)
{
    if(r<zhi)return -inf;
    if(l>=zhi)return d1[x];
    int mid=(l+r)>>1;
    return max(query1(x<<1,l,mid,zhi),query1(x<<1|1,mid+1,r,zhi));
}
ll query2(int x,int l,int r,int zhi)
{
    if(r<zhi)return -inf;
    if(l>=zhi)return d2[x];
    pushdown(x);
    int mid=(l+r)>>1;
    return max(query2(x<<1,l,mid,zhi),query2(x<<1|1,mid+1,r,zhi));
}
void build(int i,int l,int r)
{
	d1[i]=d2[i]=lz[i]=-inf,K2[i]=inf;
	if(l==r||l>r) return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid),build(i<<1|1,mid+1,r);
}
void modify(int i,int l,int r,int suf,ll x){
	if(d2[i]==-inf) return ;
	if(l>=suf){
		lz[i]=max(lz[i],x);
		d2[i]=max(d2[i],x-K2[i]);
		return ;
	}
	pushdown(i);
	int mid=l+r>>1;
	if(mid>=suf) modify(i<<1,l,mid,suf,x);
	modify(i<<1|1,mid+1,r,suf,x);
	d2[i]=max(d2[i<<1],d2[i<<1|1]);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%lld",&a[i][j]);
            if(i!=3)sum[i][j]=sum[i][j-1]+a[i][j];
        }
    for(int i=n;i>=1;i--)sum[3][i]=sum[3][i+1]+a[3][i];
    
    for(int i=1;i<=q;i++)
        scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].ct);
	sort(qu+1,qu+q+1,cmp);build(1,1,n);
    int cnt=1;
    for(int i=1;i<=n;i++)
    {
        modify(1,1,n,i,sum[1][i]-sum[2][i-1]);
        while(cnt<=q&&qu[cnt].l<=i)
        {
            if(qu[cnt].l>1)insert1(1,1,n,qu[cnt].r,dp[qu[cnt].l-1]-sum[2][qu[cnt].l-1]-qu[cnt].ct);
            insert2(1,1,n,qu[cnt].r,sum[1][i]-sum[2][i-1]-qu[cnt].ct,qu[cnt].ct);
            cnt++;
        }
        //printf("%d %d\n",query1(1,1,n,i),query2(1,1,n,i));
        dp[i]=max(query1(1,1,n,i),query2(1,1,n,i))+sum[2][i];
    }
    ll ans=-inf;
    for(int i=1;i<=n;i++)
        ans=max(ans,dp[i]+sum[3][i]);
    printf("%lld\n",ans);
    return 0;
}

标签:max,le,Business,int,题解,sum,li,CF1648D,dp
From: https://www.cnblogs.com/storms11/p/18429653

相关文章

  • Codeforces Round 975 (Div. 2) A~F 题解(Div.1 A~D)
    CodeforcesRound975(Div.2)A~F题解(Div.1A~D)也是补完整场了。A.MaxPlusSize枚举最大值的位置,使长度最长,更新答案。B.AllPairsSegments每个线段内部的点的答案都是一样的,在处理一下线段两边边界的点。被包含次数就是左边\(\times\)右边。用\(map\)记录答案......
  • pbootcms出现重复的两篇文章问题解决(实际只发布一篇)
    当遇到PBootCMS后台列表中只有一篇文章,但在前端却显示了两条的情况时,问题很可能出在数据库中的 ay_content_ext 表中存在两条重复的关联数据。以下是详细的解决方案步骤:解决方案步骤确定文章ID:在后台找到该文章的ID,假设ID为13。打开数据库工具:使用Navicat......
  • ABC373F 题解
    容易发现这是一个完全背包问题,我们设状态\(f_{i,j}\)表示前\(i\)个物品使用了\(j\)个容量的最大价值。容易写出转移方程式:\(f_{i,j}=\max\limits_{k=0}^{\lfloor\frac{j}{w}\rfloor}f_{i-1,j-kw}+kv-k^2\)直接dp是\(O(n^3)\)。考虑对这个dp进行优化。上面的方程容......
  • 题解:P9947 [USACO20JAN] Photoshoot B
    P9947[USACO20JAN]PhotoshootB题解纯模拟!在\(a_{1}\)算出来之后,我们就可以通过\(b\)数组可以求出以后\(a\)数组的所有元素。要判断是否为排列,我们可以使用一个\(vis\)做桶,为了保证字典序最小,我们可以从\(1\)开始枚举,每次枚举前要清空一下\(vis\)数组,最后使用......
  • 题解:Luogu CF548A Mike and Fax
    CF548AMikeandFax题解题面翻译给定一个字符串和一个整数\(k\),问是不是恰好存在\(k\)个子字符串是回文串,并且所有子字符串的长度一样长。题目上说有\(k\)个子字符串,我们就可以把字符串分成\(k\)份,如果分不成\(k\)份(也就是说长度不是\(k\)的倍数)的话,直接输出NO。......
  • 【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)
    文章目录一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码63.二维数组4.总结三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6一、sizeof和strl......
  • VS2008 应用程序配置不正确,未能启动该应用程序。重新安装程序可以修复此问题解决方法
    有时候我们把自己编译好的exe直接拷贝到别的电脑上使用时,如果那台电脑没装vs,一般程序无法运行提示:应用程序配置不正确,未能启动该应用程序。重新安装程序可以修复此问题。这是由于一般我们编译的程序都是使用的共享DLL,所以不一定保证其他机器上都有。如果使用静态DLL的话生......
  • 题解 ABC373G【No Cross Matching】/ POJ3565【Ants】
    题目描述年轻的自然主义者比尔在学校里研究蚂蚁。他的蚂蚁以生活在苹果树上的蚜虫为食。每个蚂蚁群需要自己的苹果树来养活自己。比尔有一张地图,上面标有\(n\)个蚂蚁群和\(n\)棵苹果树的坐标。他知道蚂蚁从它们的蚂蚁群到它们的取食地点,然后返回蚂蚁群,都是使用化学标记的路线......
  • 题解 CF407D【Largest Submatrix 3】/ SS240928C【c】
    题目描述给定一个\(n\timesm\)的正整数矩阵,求其中最大的满足其中不存在两个位置数值相等的子矩阵大小。\(1\leqn,m\leq400\)。本题有多种做法,而你需要寻找常数最小的做法才能通过本题。solution链表+双指针枚举上边界,逐渐下移下边界,枚举左边界,尝试双指针获得右边界......
  • 题解 ARC118E【Avoid Permutations】/ SS240928D【d】
    题目描述对于一个排列\(a\),定义其权值如下:生成一个\((n+2)\times(n+2)\)的网格图,行列标号为\(0∼n+1\),每次可以从\((i,j)\)走到\((i,j+1)\)或\((i+1,j)\),且不能走到\((i,a_i)\),权值为从\((0,0)\)走到\((n+1,n+1)\)的方案数。现在排列\(......