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

2023-10-09 09:52

本文主要是介绍2023牛客OI赛前集训营-提高组(第三场)C.分糖果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

文章目录


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

题目大意

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

T T T 组数据

对于 30 p t s 30pts 30pts 1 ≤ n ≤ 100 , 1 ≤ k ≤ n 1 \le n \le 100 , 1\le k \le n 1n100,1kn

另外 20 p t s 20pts 20pts 1 ≤ n ≤ 1 0 4 , k = 1 1\le n \le 10^4 , k = 1 1n104,k=1

另外 50 p t s 50pts 50pts 1 ≤ n ≤ 1 0 5 , 1 ≤ k ≤ n 1\le n \le 10^5 , 1\le k \le n 1n105,1kn

对于全部数据有 T ≤ 3 , ∣ a i ∣ ≤ 1 0 9 , 1 ≤ n ≤ 1 0 5 T \le 3 , |a_i| \le 10^9 , 1\le n \le 10^5 T3,ai109,1n105

做法

考试忘记加换行, 50 p t s → 0 50pts \to 0 50pts0

对于 30 p t s 30pts 30pts

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

对于 20 p t s 20pts 20pts

直接前缀和乱搞

50 p t s 50pts 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));}
}

对于 100 p t s 100pts 100pts

权值线段树 + 离散化

我们发现上面的 d p dp dp 转移太慢了

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

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


f [ i ] = M A X j = 1 i f [ j ] + 1 ( s [ i ] − x ≤ s [ j ] ) f[i] = MAX_{j = 1}^i f[j] + 1(s[i] - x \le s[j]) f[i]=MAXj=1if[j]+1(s[i]xs[j])
用权值线段树维护就好了。

初始化 f [ 0 ] = 0 f[0] = 0 f[0]=0

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

因为总和太大了,所以还要把 s [ i ] s[i] s[i] s [ i ] − x s[i] - x s[i]x 拿出来离散化(还有 0 0 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));}
}

这篇关于2023牛客OI赛前集训营-提高组(第三场)C.分糖果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/172026

相关文章

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

键盘快捷键:提高工作效率与电脑操作的利器

键盘快捷键:提高工作效率与电脑操作的利器 在数字化时代,键盘快捷键成为了提高工作效率和优化电脑操作的重要工具。无论是日常办公、图像编辑、编程开发,还是游戏娱乐,掌握键盘快捷键都能带来极大的便利。本文将详细介绍键盘快捷键的概念、重要性、以及在不同应用场景中的具体应用。 什么是键盘快捷键? 键盘快捷键,也称为热键或快捷键,是指通过按下键盘上的一组键来完成特定命令或操作的方式。这些快捷键通常涉及同

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

如何提高 GitHub 的下载速度

如何提高 GitHub 的下载速度 文章目录 如何提高 GitHub 的下载速度1. 注册账号2. 准备好链接3. 创建仓库4. 在码云上下载代码5. 仓库更新了怎么办 一般来说,国内的朋友从 GitHub 上面下载代码,速度最大是 20KB/s,这种龟速,谁能忍受呢? 本文介绍一种方法——利用“码云”,可以大大提高下载速度,亲测有效。 1. 注册账号 去“码云”注册一

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

如何提高开发的效率,让老板不知所措的给你发工资

设计模式 UML JSP 编程 数据结构 1.你可能会常常发现,写了一段代码后,编译程序时是一大堆的出错 (原因:语法不熟)  ──别担心,这是每个程序员必须经历的事,这时候你就需要更大的耐心及细心,对每一行代码进行仔细人阅读并改正,这个很重要,这可以培养你的理解代码能力,所以要常读程序,不要等到程序运行以后才知道你的程序的结果。  ──如何避免:在写代码以前,要认真的学习计算机语

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比

Java开发实例大全提高篇——Applet的应用

开发十年,就只剩下这套架构体系了! >>>    第21章  Applet的应用 21.1  Applet在html中的使用 实例549  在html中显示Applet HtmlShowApplet.java     public void paint(Graphics g){         g.drawString("html文件已经运行", 50, 50);// 绘制文本