首页 > 其他分享 >2023牛客OI赛前集训营-提高组(第三场)C.分糖果

2023牛客OI赛前集训营-提高组(第三场)C.分糖果

时间:2023-10-08 17:33:31浏览次数:37  
标签:le return OI ss tr mid int 集训营 第三场

2023牛客OI赛前集训营-提高组(第三场)C.分糖果

目录

C-分糖果_2023牛客OI赛前集训营-提高组(第三场) (nowcoder.com)

题目大意

求前 \(i(i\in[1, n])\) 个数分成 \(k\) 个连续的区间,每一个区间和的最大值最小是多少。

\(T\) 组数据

对于 \(30pts\) ,\(1 \le n \le 100 , 1\le k \le n\)

另外 \(20pts\) ,\(1\le n \le 10^4 , k = 1\)

另外 \(50pts\),\(1\le n \le 10^5 , 1\le k \le n\)

对于全部数据有 \(T \le 3 , |a_i| \le 10^9 , 1\le n \le 10^5\)

做法

考试忘记加换行,\(50pts \to 0\)

对于 \(30pts\)

直接二分答案 + \(dp\) , \(O(n^2)\) 判断能不能分成大于等于 \(k\) 块的和满足假设。

对于 \(20pts\)

直接前缀和乱搞

\(50pts\) 代码

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define LL long long
using namespace std;
const int N = 1e5 + 5 , M = 1e5 + 5;
const LL inf = 1e14 + 5;
int n , k;
LL a[M] , f[M] , s[M] , ans;
bool ck (LL x) {
    int l = 1;
    fu (i , 1 , n) f[i] = 0;
    fu (i , 1 , n) {
        if (i == 1) {
            f[i] = (s[1] <= x);
        }
        else {
            fu (j , 1 , i) {
                if (s[i] - s[j - 1] <= x && (f[j - 1] || j == 1)) f[i] = max (f[i] , f[j - 1] + 1);
            }
        }
        if (f[i] >= k) return 1;
    }
    return 0;
}
LL fans (LL l , LL r) {
    if (l == r) {
        return ck (l) ? l : inf;
    }
    LL mid = l + r >> 1;
    if (ck (mid)) return min (fans (l , mid) , mid);
    else return min (inf , fans (mid + 1 , r));
}
int main () {
    // freopen ("candy2.in" , "r" , stdin);
    int T; 
    scanf ("%d" , &T);
    while (T --) {
        scanf ("%d%d" , &n , &k);
        fu (i , 1 , n) scanf ("%lld" , &a[i]) , s[i] = 0;
        fu (i , 1 , n) s[i] = s[i - 1] + a[i];
        if (k == 1) {
            ans = inf;
            fu (i , 1 , n) ans = min (ans , s[i]);
            printf ("%lld\n" , ans);
            continue;
        }
        printf ("%lld\n" , fans (-inf , inf));
    }
}

对于 \(100pts\)

权值线段树 + 离散化

我们发现上面的 \(dp\) 转移太慢了

\(s\) 数组表示前缀和 ,当前二分答案为 \(x\)

对于 \(i\in[1 , n]\) 我们只用找到 \(j\in[1 , i]\) 满足 \(s[i] - s[j] \le x\) 即 \(s[i] - x \le s[j]\) 时的最大值 \(+1\)

\[f[i] = MAX_{j = 1}^i f[j] + 1(s[i] - x \le s[j]) \]

用权值线段树维护就好了。

初始化 \(f[0] = 0\)

每次把 \(f[i]\) 插入权值线段树中

因为总和太大了,所以还要把 \(s[i]\) 和 \(s[i] - x\) 拿出来离散化(还有 \(0\)) ,动态开点。

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define LL long long
using namespace std;
const int N = 4e7 + 5 , M = 2e5 + 5;
const LL inf = 1e9 * 1e6;
const int inff = 1e9 + 5;
int n , k , cnt , mp[M];
LL a[M] , f[M] , s[M] , ans , ss[M << 1];
struct Tr {
    int v , lp , rp;
} tr[N];
void glp (int p) {
    if (!tr[p].lp) {
        tr[p].lp = ++cnt;
        tr[cnt].v = -inff;
    }
}
void grp (int p) {
    if (!tr[p].rp) {
        tr[p].rp = ++cnt;
        tr[cnt].v = -inff;
    }
}
void change (int p , LL l , LL r , int x , int val) {
    if (l == r) tr[p].v = max (tr[p].v , val);
    else {
        int mid = l + r >> 1;
        if (x <= mid) {
            glp (p);
            change (tr[p].lp , l , mid , x , val);
        }
        else {
            grp (p);
            change (tr[p].rp , mid + 1 , r , x , val);
        }
        tr[p].v = max (tr[tr[p].lp].v , tr[tr[p].rp].v);
    }
}
int query (int p , LL l , LL r , LL L , LL R) {
    if (L <= l && R >= r) return tr[p].v;
    else {
        int mid = l + r >> 1 , ans1 = -inff , ans2 = -inff;
        if (L <= mid && tr[p].lp) 
            ans1 = query (tr[p].lp , l , mid , L , R);
        if (R > mid && tr[p].rp) 
            ans2 = query (tr[p].rp , mid + 1 , r , L , R);
        return max (ans1 , ans2);
    }
}
void cl (int p) { tr[p].lp = tr[p].rp = 0 , tr[p].v = -inff; }
void clear (int p , LL l , LL r) {
    if (l == r) {
        cl (p);
        return;
    }
    int mid = l + r >> 1;
    if (tr[p].lp) 
        clear (tr[p].lp , l , mid);
    if (tr[p].rp)
        clear (tr[p].rp , mid + 1 , r);
    cl (p);
} 
bool ck (LL x) {
    int s1 = 1;
    ss[1] = 0;
    fu (i , 1 , n) {
        ss[++s1] = s[i];
        ss[++s1] = s[i] - x;
    }
    sort (ss + 1 , ss + s1 + 1);
    int m = unique (ss + 1 , ss + s1 + 1) - ss - 1;
    clear (1 , -M , M);
    tr[0].v = -M;
    cnt = 1;
    int y = lower_bound(ss + 1 , ss + s1 + 1 , 0) - ss;
    change (1 , -M , M , y , 0);
    fu (i , 1 , n) {
        y = lower_bound(ss + 1 , ss + s1 + 1 , s[i] - x) - ss;
        f[i] = query (1 , -M , M , y , M) + 1;
        y = lower_bound(ss + 1 , ss + s1 + 1 , s[i]) - ss;
        change (1 , -M , M , y , f[i]);
        if (f[i] >= k) return 1;
    }
    return 0;
}
LL fans (LL l , LL r) {
    if (l == r) return ck (l) ? l : inf;
    else {
        LL mid = l + r >> 1;
        if (ck (mid))  {
            return min (fans (l , mid) , mid);
        }
        else {
            return fans (mid + 1 , r);
        }
    }
}
int main () {
    // freopen ("candy2.in" , "r" , stdin);
    int T; 
    scanf ("%d" , &T);
    while (T --) {
        scanf ("%d%d" , &n , &k);
        fu (i , 1 , n) scanf ("%lld" , &a[i]) , s[i] = 0;
        fu (i , 1 , n) s[i] = s[i - 1] + a[i];
        printf ("%lld\n" , fans (-inf , inf));
    }
}

标签:le,return,OI,ss,tr,mid,int,集训营,第三场
From: https://www.cnblogs.com/2020fengziyang/p/17749697.html

相关文章

  • android: 通过Intent筛选多种类型文件
     一般使用setType()方法来实现文件过滤,如:只显示PDF文件:intrequestCode=100;Intentintent=newIntent(Intent.ACTION_GET_CONTENT);intent.setType("application/pdf");intent.addCategory(Intent.CATEGORY_OPENABLE);startActivityFor......
  • LY1366 [ 20231005 NOIP 模拟赛 T0 ] 加固
    题意设\(T\)是由\(26\)小写英文字母排列得到的字符串。\(T'\)由\(T\)复制若干次得到。给定字符串\(S\)为\(T'\)的子序列,求\(T'\)的最小复制次数。保证出现的不同字母不超过\(20\)种\(1\le|S|\le10^5\)Sol一个巧妙的转化,考虑将\(T\)串作为字典序,那么当......
  • Rethinking Point Cloud Registration as Masking and Reconstruction论文阅读
    RethinkingPointCloudRegistrationasMaskingandReconstruction2023ICCV*GuangyanChen,MeilingWang,LiYuan,YiYang,YufengYue*;ProceedingsoftheIEEE/CVFInternationalConferenceonComputerVision(ICCV),2023,pp.17717-17727paper:Rethin......
  • LY1374 [ 20231008 NOIP 模拟赛 T2 ] 机房惨案
    题意给定一棵树,每次操作将一个点染成黑色。求询问的点到所有黑点的路径编号最小值。**数据保证第一次为染色操作**Sol注意到保证第一次为染色。考虑钦定根节点为染色的点。那么对于所有染色操作,暴力记录染色的点到根节点的路径上所有点的贡献。每个点只会贡献一次,这部分......
  • 使用MPAndroidChart实现心跳图
    简介这篇文章主要介绍如何使用MPAndroidChart实现心跳图的效果。需求分析之前考虑过用2个linechart上下叠起来,坐标轴上下设置了默认空格,数据需要处理坐标轴为0的情况,多个数据处理比较复杂,数据处理和UI效果不尽如意,最终考虑使用单个linechartview来实现效果,在数据方面我们主要......
  • Android三方支付对接方案
    场景用户在APP中下单,跳转到支付宝/微信中完成支付,支付完后跳回到APP内,展示支付结果。支付宝对接接入前准备https://opendoc.alipay.com/open/204/105051?pathHash=b91b9616https://opendocs.alipay.com/open/204/01dcc0步骤添加支付宝sdk依赖。apicom.alipay.sdk:alip......
  • Mysql join算法深入浅出
    导语联表查询在日常的数据库设计中非常的常见,但是联表查询可能会带来性能问题,为了调优、避免设计出有性能问题的SQL,在explain命令中,会显示用的是哪个join算法,学习一下join过程是非常有必要的当执行下面这个SQLJoin,在不同的情况下会产生不一样的复杂度select*fromusertb1l......
  • python queue join task_done的概念及实例解析
    一概念Queue.task_done()在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号Queue.join()实际上意味着等到队列为空,再执行别的操作。 二实例源码一importthreadingimportqueueimporttime#创建队列,用于存储数据q=queue.Qu......
  • Error while loading conda entry point: conda-libmamba-solver (libarchive.so.19:
    本人使用centos:7.6.1810及Miniconda3-py311_23.5.2-0-Linux-x86_64默认状态下应该没有这个问题。当在使用conda下载包时,如果不小心更新了涉及conda-libmamba-solver和libarchive的包,就可能会导致这个报错消息出现。Errorwhileloadingcondaentrypoint:conda-libmamb......
  • P1003 [NOIP2011 提高组] 铺地毯
    第一思路:开一个N*N的数组,每次都扫一遍地毯范围并标记编号然后你会发现:喜提MLE为什么呢?我们来看看数据范围0≤n≤1e4n的范围是1e4,数组总大小为1e16,大约需要4000TB的内存空间服务器也不带这么玩的正解:将地毯信息用结构体存储structnode{ intx1,y1,x2,y2;//x1......