首页 > 其他分享 >BZOJ 生日礼物

BZOJ 生日礼物

时间:2023-09-24 17:04:16浏览次数:50  
标签:lld int positive LL 生日礼物 ans 正数 BZOJ

题目背景

翰翰 18 岁生日的时候,达达给她看了一个神奇的序列 $ A_1,A_2,\dots ,A_n $ 。她被允许从中选择不超过 $ M $ 个连续的部分作为自己的生日礼物。

翰翰想要知道选择元素之和的最大值。

你能帮助她吗?

解题思路

可以先合并序列中连续的同为正或负的值,使原序列变为一个一正一负排列的序列。

先将所有正数相加存入 $ ans $ ,记录目前的段数 $ positive $ ,因为只取 $ M $ 段,我们可以尝试以下方法。

  • 减去一个正数。
  • 加上一个负数,并使相邻的正数连成一段。

上述两种操作均会使目前的段数 $ positive-1 $ ,直到 $ positive=M $ 时,最终的 $ ans $ 就是我们想要的结果。

而我们想要 $ ans $ 尽量大,所以减去的正数要尽量小或加上的负数要尽量大,等价于求 $ \left| A_i \right|_ {min} $ 。所以我们可以将所有数取绝对值存入小根堆,每次找堆顶操作。连成一段的操作可以用链表修改前驱和后继,使其连成一段。

注意: 若最左边和最右边的值为负的,显然是不用取的,需要特判一下。

代码

#include<cstdio>
#include<queue>
using namespace std;
typedef long long LL;
constexpr int N=1e6+10;
constexpr LL inf=1e18;
typedef pair<LL,LL> PII;
priority_queue<PII,vector<PII>,greater<PII>>q;
LL n,m,positive,maxn;
LL d[N],l[N],r[N];
bool v[N];
bool check_symbols(LL x,LL y)
{
    if((x>=0&&y>=0)||(x<0&&y<0))return 1;
    return 0;
}
LL abs(LL x){return x>0?x:-x;}
void remove(int x)
{
    l[r[x]]=l[x];
    r[l[x]]=r[x];
    v[x]=true;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    LL dlen=1;
    scanf("%lld",&d[dlen]);
    for(int i=2,x;i<=n;i++)
    {
        scanf("%lld",&x);
        if(!x)continue;
        if(check_symbols(d[dlen],x))
            d[dlen]+=x;
        else 
            d[++dlen]=x;
    }
    LL ans=0;
    for(LL i=1;i<=dlen;i++)
    {
        l[i]=i-1;r[i]=i+1;
        if(d[i]>0)ans+=d[i],positive++;
        q.push({abs(d[i]),i});
    }
    while(positive>m)
    {
        PII con=q.top();
        q.pop();
        int x=con.second;
        if(v[x])continue;
        if(d[x]>0||(l[x]!=0&&r[x]!=dlen+1))
        {
            ans-=con.first;
            d[x]+=d[l[x]]+d[r[x]];
            q.push({abs(d[x]),x});
            remove(r[x]);
            remove(l[x]);
            --positive;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

还是很水的啊。我不说是谁做了一天

标签:lld,int,positive,LL,生日礼物,ans,正数,BZOJ
From: https://www.cnblogs.com/lofty2007/p/17726178.html

相关文章

  • BZOJ 3509
    题目链接description给定一个长度为\(n\)的数组\(a\),求有多少对\(i,j,k(1\leqi<j<k\leqn)\)满足\(a_k-a_j=a_j-a_i\)\(n\leq10^5\)值域大小3e4.solution三个数,看起来就不好用数据结构维护。\(2a_j=a_i+a_k\)可以当做多项式两项的指数相加得到指数为\(2a_j\)的......
  • BZOJ 3451
    题目链接description厉害题。给定一棵树,按照题面要求求一个错误点分治的期望执行次数。(不想描述题面了qwq)solution考虑拆开计算每个点期望几层点分治后被删除。这个期望值显然就是它对答案的贡献。我们不妨以这个点为根,那么相当于要求每次删除一个未被删除的点的子树,求删完......
  • BZOJ3309 DZY Loves Math
    题目大意对于正整数\(n\),定义\(f(n)\)为\(n\)所包含质因子的最大幂指数。例如\(f(1960)=f(2^3\times5^1\times7^2)=3\),\(f(10007)=1\),\(f(1)=0\)。给定正整数\(a,b\),求下式的值:\[\sum^{a}_{i=1}\sum^{b}_{j=1}f(\gcd(i,j))\]推导首先记\(n=\min(a,b),m=\max(a,b)......
  • TZOJ8036--生日礼物
    题目简述:给你n个数,让你选取不超过m个连续的区间,区间不重叠,求区间总和最大。标准输入522-32-12标准输出5思路:1.很显然能够想到把原数组简化成形如一正一负的数组。2.特殊情况,当正数连续块小于等于m时答案很显然是所有正数相加。3.一般情况,当正数连......
  • [BZOJ 4361] isn
    简述题意给出一个长度为\(n\)的序列\(A(A_1,A_2,\dots,A_n)\)。如果序列\(A\)不是非降的,你必须从中删去一个数,并重复这一操作,直到\(A\)非降为止。求有多少种不同的操作方案,答案模\(10^9+7\)。题面转换......
  • 【BZOJ 3364】Distance Queries 距离咨询 题解
    原题简化题意:有一棵\(n\)个点的树,\(q\)组询问,每次询问回答两点间的距离。令\(dis[i][j]\)表示\(i\)到\(j\)的距离,根节点为\(rt\),则有\(dis[i][j]=dis[rt][i]+dis[rt][j]-2×dis[rt][lca(i,j)]\),按照题意打即可。#include<bits/stdc++.h>usingnamespacestd;#d......
  • BZOJ3337 ORZJRY I 题解
    https://vjudge.net/problem/黑暗爆炸-3337题意试维护一个序列,支持以下\(11\)种操作:输入格式说明1xw在\(a_x\)后插入\(w\)2x删除\(a_x\)3xy翻转\((a_x,a_{x+1},\dots,a_y)\)4xyk将\((a_x,a_{x+1},\dots,a_y)\)右移\(k\)次......
  • BZOJ 4321 queue2 题解
    在硬盘里翻到了当时没推完的这个题,今天补完了最后几步。题目链接:https://hydro.ac/d/bzoj/p/4321对任意相邻两个元素差的绝对值不为\(1\)的\(n\)阶排列计数。\(\mathcal{O}(n^2)\)做法是考虑按照值域由小到大逐步插入,记录\(f_{i,j}\)为长度为\(i\)的排列,一共有\(j\)......
  • 题解 BZOJ4543【[POI2014] HOT-Hotels】
    长链剖分优化DP板子题了,但是虽然是板子这个转移方程也很难想。problem树。求\(\sum_{1\leqi<j<k\leqn}[dist(i,j)=dist(i,k)=dist(j,k)].\)。\(n\leq10^5\)。solution与重链剖分相似,长链剖分是将树剖成很多条长链。我们定义长儿子,为一个点的儿子中子树深度最大的一个儿......
  • 【求助+半题解】BZOJ1461字符串的匹配
    先说思路:因为我们是比对较短的\(B\)与较长的\(A\)的子串,所以我们求不变的\(B\)的\(next\)对于这道题我们可以使用树状数组查询前缀和维护数的排名。对于相同的数我们查询的排名是有误的,因此不仅要比对小于等于该数的前缀和,也要比对小于该数的前缀和。如:对于\(A=2\)\(2\),\(B......