洛谷 P5665 [CSP-S2019] 划分
链接:
题意:
给出 \(n\) 个整数 \(a_i\) ,你需要找到一些分界点 \(1 \leq k_1 \lt k_2 \lt \cdots \lt k_p \lt n\),使得
\(\sum\limits_{i=1}^{k_1} a_i \leq \sum\limits_{i=k_1+1}^{k_2} a_i \leq \cdots \leq \sum\limits_{i=k_p+1}^{n} a_i\)。
注意 \(p\) 可以为 \(0\) 且此时 \(k_0 = 0\)。
请你最小化
\((\sum\limits_{i=1}^{k_1} a_i)^2 + (\sum\limits_{i=k_1+1}^{k_2} a_i)^2 + \cdots + (\sum\limits_{i=k_p+1}^{n} a_i)^2\)。
分析:
根据完全平方公式有:\((a+b)^2\geq a^2+b^2\)
所以分段比不分段更优。其次,对于一个数 \(x\),将他分到左边和右边会造成 \(2x*sum_{side}+x^2\) 的贡献(\(sum\) 指两区间和),又因为 \(sum_L\leq sum_R\) 所以尽量分到左边更优。也就是说,最后一段和最小时,答案最优。(这个策略还是能猜出来,只是不敢确定)。于是就有后面的\(O(n^2)\) dp 了。
算法:
首先维护一个前缀和 \(sum\) (和上文 \(sum\) 不同)。设 \(d[i]\) 为 \(i\) 结尾,最后一段最小时上一段的结尾位置,于是有 \(d[i]=max\{j|sum[i]-sum[j]\geq sum[j]-sum[d[j]]\}\)。从 \(i\) 向左循环遇到的第一个满足条件的位置就是 \(d[i]\)。输出时从 \(n\) 不停向它的 \(d\) 值跳,一直跳到 \(0\)。复杂度 \(O(n^2)\)。
优化:
根据上述算法可以写出这样的程序:
for(int i=1;i<=n;i++){
for(int j=i-1;j>=1;j--)
if(sum[i]-sum[j]<sum[j]-sum[d[j]]) continue;
d[i]=j; break;
}
int now=n;
while(now){
int t=sum[now]-sum[d[now]];
ans+=t*t;
now=d[now];
}
\(O(n^2)\) 复杂度可以通过64分的好成绩,但是看到 \(2\leq n\leq4\times10^7\),这说明我们需要一个 \(O( n )\) 或实(hen)现(neng)良(ka)好(chang)的 \(O(n\log n)\)。
回顾算法,发现判断 \(j\) 是否合法时的柿子:
\(sum[i]-sum[j]\geq sum[j]-sum[d[j]]\)
可以继续改写:
\(2*sum[j]-sum[d[j]]\leq sum[i]\)
此时左边只与 \(j\) 有关右边只与 \(i\) 有关。设 \(A(j)=2*sum[j]-sum[d[j]]\) 。显然 \(A(j)\) 越小,\(j\) 越可能成为合法答案,所以当存在 \(j_1<j_2\) 且 \(A(j_1)>A(j_2)\) 时,\(j_2\) 比 \(j_1\) 更优。
又有 \(sum[i]\lt sum[i+1]\) 所以当一个 \(j\) 满足 \(A(j)\leq sum[i]\) 时,它也满足 \(A(j)\leq sum[i+1]\)。
基于以上两点我们可以维护出一个 \(A(j)\) 单调上升且 \(j\) 单调上升的单调队列,每次转移时找到最大的满足 \(A(j)\leq sum[i]\) 的 \(j\),小于 \(j\) 的状态可以舍弃,更新 \(d[i]\) 后将 \(A(i)\) 加入队列尾并弹出 \(A(k)>A(i)\) 的状态 \(k\),每个点最多进出1次,所以复杂度是 \(O(n)\)。
于是我们可以这样维护 \(d[i]\):
for(int i=1;i<=n;i++){
while(head<tail&&A(q[head+1])<=sum[i])head++;
d[i]=q[head];
while(head<tail&&A(i)<A(q[tail]))tail--;
q[++tail]=i;
}
另外的,此题最后三个测试点相当毒瘤,输入相当占时间和空间,数据范围会爆 long long
。我们不得不选择高精(或考场上不敢写的__int128),同时需要对空间和时间能够精确把控,最好还是自己慢慢调,可以锻炼自己的代码能力。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=4e7+5;
ll sum[N];
int d[N],q[N],n,type,head,tail;
inline __int128 A(int i){return 2*sum[i]-sum[d[i]];}
//sub23~25
const int M=1e5+5;
const int mod=1ll<<30;
ll x,y,z,m;
int p[M],l[M],r[M];
ll b[N];
//
__int128 ans;
void print(__int128 x){
if(x==0){
cout<<0;
return ;
}
string res="";
while(x){
res+=x%10+'0';
x/=10;
}
reverse(res.begin(),res.end());
cout<<res;
}
signed main(){
n=in,type=in;
if(type==0)
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+in;
else{
x=in,y=in,z=in,b[1]=in,b[2]=in,m=in;
for(int i=1;i<=m;i++)
p[i]=in,l[i]=in,r[i]=in;
for(int i=3;i<=n;i++)
b[i]=((x*b[i-1]%mod+y*b[i-2]%mod)%mod+z)%mod;
int now=0;
for(int i=1;i<=n;i++){
if(i>p[now])now++;
sum[i]=sum[i-1]+b[i]%(r[now]-l[now]+1)+l[now];
}
}
for(int i=1;i<=n;i++){
while(head<tail&&A(q[head+1])<=sum[i])head++;
d[i]=q[head];
while(head<tail&&A(i)<A(q[tail]))tail--;
q[++tail]=i;
}
int now=n;
while(now){
__int128 t=sum[now]-sum[d[now]];
ans+=t*t;
now=d[now];
}
print(ans);
return 0;
}
可能是因其毒瘤的数据才成为了紫题
洛谷 P5665 [CSP-S2019] 划分的更多相关文章
- 洛谷P4047 [JSOI2010]部落划分题解
洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...
- uoj#348/洛谷P4221 [WC2018]州区划分(FWT)
传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...
- 【CSP-S 2019】【洛谷P5665】划分【单调队列dp】
前言 \(csp\)时发现自己做过类似这道题的题目 : P4954 [USACO09Open] Tower of Hay 干草塔 然后回忆了差不多\(15min\)才想出来... 然后就敲了\(88p ...
- 洛谷——P1025 数的划分
P1025 数的划分 题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有 ...
- 洛谷 P1025 数的划分 Label:dp
题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...
- 洛谷 P1025 数的划分
题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...
- [NOIP2001] 提高组 洛谷P1025 数的划分
题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...
- 洛谷P1025 数的划分【dp】
将整数nn分成kk份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7n=7,k=3k=3,下面三种分法被认为是相同的. 1,1,51,1,5; 1,5,11,5,1; 5,1,15, ...
- nbuoj 2080 洛谷p1025 数的划分
链接:http://www.nbuoj.com/v8.83/Problems/Problem.php?pid=2820 链接:https://www.luogu.org/problem/P1025 题 ...
随机推荐
- RSA及其证明 [原创]
描述RSA的实现步骤介绍文章非常多,但说明并证明其原理,并进而讨论为什么这样设计的文章不多.本人才疏学浅,不敢说理解了R.S.A.三位泰斗的设计初衷,简单就自己的理解写一写,博大家一笑. 以下原创内容 ...
- oracle table()函数
PL/SQL表---table()函数用法/* PL/SQL表---table()函数用法:利用table()函数,我们可以将PL/SQL返回的结果集代替table. oracle内存表在查询和报表的 ...
- lua中的随机数
Lua 生成随机数需要用到两个函数:math.randomseed(xx), math.random([n [, m]]) 1. math.randomseed(n) 接收一个整数 n 作为随机序列种 ...
- Docker系列(2)- Docker中的名词概念
Docker工作流程 名词概念 镜像(image): docker镜像就好比一个模板,可以通过这个模板来创建容器服务,tomcat镜像===>run===>tomcat01(提供服务器) ...
- Jmeter系列(23)- 常用逻辑控制器(2) | 事务控制器Transaction Controller
事务控制器(Transaction Controller) 作用 选择一些请求,作为事务,放在该控制器下 比如:我有三个请求,注册.登录.下单.这三个请求其实就是一个下单完成过程,可以作为一个下单事务 ...
- 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01
百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
- CF666E-Forensic Examination【广义SAM,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/CF666E 解题思路 给出一个串\(S\)和\(n\)个串\(T_i\).\(m\)次询问\(S_{a\sim b} ...
- P3971-[TJOI2014]Alice and Bob【贪心】
正题 题目链接:https://www.luogu.com.cn/problem/P3971 题目大意 一个\(1\sim n\)的一个排列,设\(a_i\)表示以\(i\)结尾的最长上升子序列长度, ...
- P4480-[BJWC2018]餐巾计划问题【三分,贪心】
正题 题目链接:https://www.luogu.com.cn/problem/P4480 题目大意 \(n\)天,第\(i\)天需要\(a_i\)个餐巾. 每个餐巾价格为\(p\),使用完后有两种 ...
- PC Register简介
PC Regiter介绍: JVM中的程序计数寄存器(Program Counter Register)中,Register的命名源于CPU的寄存器,寄存器存储指令相关的现场信息,CPU只有把数据装载 ...