惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
H
Help Net Security
B
Blog RSS Feed
G
Google Developers Blog
博客园 - 司徒正美
MongoDB | Blog
MongoDB | Blog
量子位
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
P
Proofpoint News Feed
小众软件
小众软件
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
V
V2EX
月光博客
月光博客
C
Check Point Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
Arctic Wolf
Help Net Security
Help Net Security
Schneier on Security
Schneier on Security
D
DataBreaches.Net
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Palo Alto Networks Blog
T
Tenable Blog
L
LangChain Blog
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
大猫的无限游戏
大猫的无限游戏
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Y
Y Combinator Blog
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
NISL@THU
NISL@THU
GbyAI
GbyAI
博客园 - Franky
S
Secure Thoughts
有赞技术团队
有赞技术团队
PCI Perspectives
PCI Perspectives
U
Unit 42

AirTouchの小站

DNSMgr——聚合管理所有域名DNS解析+自动续签SSL证书并部署 | AirTouchの小站 雨云香港服务器简单测评 | AirTouchの小站 七牛云 AI 狂送 token 实测到底怎么样 | AirTouchの小站 记一次博客被攻击 | AirTouchの小站 给你的 Artalk 评论区配置验证码和垃圾评论检测 | AirTouchの小站 抓紧上车!免费 E3 开发者账号又来了! | AirTouchの小站 Vercel & Cloudflare Worker 项目推荐(2) | AirTouchの小站 用 Zmail 搭建自己的临时邮箱 | AirTouchの小站 IPv6反解域名?手把手带你搞 | AirTouchの小站 AirTouchの小站 AirTouchの小站 AirTouchの小站 AirTouchの小站 AirTouchの小站 macOS Tahoe 26中Electron架构卡顿的临时解决方案 | AirTouchの小站 用Obsidian插件增强Stellar写作体验 | AirTouchの小站 复习一下最小生成树 | AirTouchの小站 2025苹果秋季发布会亮点总结 | AirTouchの小站 分享几个artalk邮件通知模板 | AirTouchの小站 博客的图片应该存哪啊? | AirTouchの小站 Pic Smaller——自部署压缩图片的利器 | AirTouchの小站 企业微信的自定义域名邮箱太香了 | AirTouchの小站 所有道听途说,终获眼见为实 | AirTouchの小站 修复Vercel部署hexo导致文章的更新时间错误 | AirTouchの小站 jsDelivr国内公益加速镜像分享 | AirTouchの小站 搭建自己的busuanzi访问量统计服务 | AirTouchの小站 用Vercel和Netlify反代你的网站 | AirTouchの小站 用EdgeOne配置反向代理 丢掉丑陋的端口号 | AirTouchの小站 拼好鸽香港4区nat机器:月付3.5还要啥自行车! | AirTouchの小站 博客的新域名——xsl.im | AirTouchの小站 如何搭建自己的EdgeOne优选域名 | AirTouchの小站 用EdgeOne加速CloudflareR2存储桶 | AirTouchの小站 EdgeOne自动化上传证书并部署 | AirTouchの小站 你需要把PicGo换成PicList了! | AirTouchの小站 Cursor屏蔽中国大陆?给你解决方案! | AirTouchの小站 使用 Cloudflare Workers 自动获取必应每日壁纸 | AirTouchの小站 题解:P9509『STA - R3』Aulvwc | AirTouchの小站 题解:P11140 [APC001] E - Linear Map | AirTouchの小站 Phira多人联机服务器搭建&使用教程 | AirTouchの小站 腾讯云EdgeOne免费CDN加速你的网站 | AirTouchの小站 Hexo 博客收录指南 | AirTouchの小站 Cloudflare CDN优选IP加速你的网站 | AirTouchの小站 Giffgaff在线生成esim二维码 | Giffgaff sim转eSIM指南 | AirTouchの小站 AirTouchの小站 AirTouchの小站 Hexo Stellar 主题装修笔记 | AirTouchの小站 AirTouchの小站 AirTouchの小站 AirTouchの小站
题解:P12646 [KOI 2024 Round 1] 升序 | AirTouchの小站
AirTouch, me@airtouch.top · 2025-07-09 · via AirTouchの小站

A 掉这道题才发现自己是第 9 个 A 的,抓紧来发篇题解。

题目传送门

www.luogu.com.cn

https://www.luogu.com.cn/problem/P12646

题意理解

一看到这道题,我发现其实就是 [KOI 2024 Round 1] 加倍 的加强版,多了一个区间查询。

题意:给你一个长度为 MM 的正整数序列 X1,X2,…,XMX_1,X_2, \dots,X_M,给你 l,rl,r,每次操作可以把 XiX_i22,求出让 Xl,Xl+1,…,XrX_l, X_{l+1}, \dots, X_r 变为升序的最小操作次数。

解题思路

简化一下,对于 ∀i,Xi≤Xi+1×2ci\forall i,X_i \leq X_{i+1} \times 2^{c_i},我们可以把每个 cic_i 存下来,如果 XiX_i 乘了 11 次,那么后面的 XjX_j 都会多乘 11 次,所以前面的会对后面的产生影响,那么就要计算前缀和,它们的前缀和加起来就是答案————————吗?

举个例子,序列 3,1,5,1,53,1,5,1,5 ,其对应的 cic_i 分别为 2,0,3,02,0,3,0,前缀和就是 2,2,5,52,2,5,5,结果为 1414,很明显是不对的。

思考一下,发现需要计算每个 XiX_i 可以抵消掉后面的次数,那么这个 cic_i 就分别是 2,−2,3,−22,-2,3,-2,前缀和加起来就是 66,这才是正确的。

But,序列 1,10,51,10,5cic_i−3,1-3,1,但是前缀和加起来就是 −5-5,很明显的错误,所以如果前缀和变成了负数,要令其变为 00

综上,我们可以归纳出,cic_iXiX_iXi+1X_{i+1} 之间的变化,前缀和 Si=max⁡(0,Si−1+ci)S_i = \max(0, S_{i-1}+c_i),对于区间 l,rl,r,答案就是 ∑i=lrSi\sum_{i=l}^r S_i,如果每次跑一遍累加一下,复杂度是 O(MQ)O(MQ),只能得到 12pts。

考虑优化,将 ∑i=lrSi\sum_{i=l}^r S_i 拆开,得到 ∑i=lr∑j=licj\sum^r_{i=l} \sum^i_{j=l} c_j,交换两个求和符号得 ∑j=lr∑i=jrcj\sum^r_{j=l} \sum^r_{i=j} c_j,再化简一下是 ∑j=lr(r−j+1)cj\sum^r_{j=l}(r-j+1)c_j,将 (r+1)(r+1) 提出来得 (r+1)∑j=lrcj−∑j=lrj×cj(r+1)\sum^r_{j=l} c_j-\sum^r_{j=l}j\times c_j,所以这就是答案的式子,可以用两个前缀和维护,就可以实现 O(1)O(1) 查询,但是由于 Si=max⁡(0,Si−1+ci)S_i = \max(0, S_{i-1}+c_i),设 Ri=Ri−1+ciR_i=R_{i-1}+c_i,所以这个式子只能用于 Ri≥0R_i ≥ 0 的区间。

对于 Ri<0R_i < 0 的情况,可以考虑分段,将连续的 Ri(Ri≥0)R_i(R_i ≥ 0) 分为一段,由于这一段 Ri≥0R_i ≥ 0,所以就可以用 (r+1)∑j=lrcj−∑j=lrj×cj(r+1)\sum^r_{j=l} c_j-\sum^r_{j=l}j\times c_j 算出每一段的答案,再拼成 l,rl,r 的区间。

如何实现呢?我们知道,如果 Rj<Ri(j>i)R_j<R_i (j>i),那么这一段就是 <0<0 的,所以需要找到第一个比 RiR_i 小的 RjR_j,可以用单调栈维护,存入 nxtinxt_i 表示第一个比 RiR_i 小的 RjR_jjj

代码实现

复杂度大约是 O(Q)O(Q),注意开 long long

cpp
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=3e5+10;
int n,q,a[N],c[N],sum,cnt,s[N],ss[N],nxt[N];
stack<int> st;
int getsum(int l,int r){
	return (r+1)*(s[r]-s[l-1])-(ss[r]-ss[l-1]);
}
void zj(){
	//预处理nxt[i]
	for(int i=n;i>=0;i--){
		while(!st.empty()&&s[st.top()]>=s[i]) st.pop();
		if(!st.empty()) nxt[i]=st.top();
		else nxt[i]=n+1;
		st.push(i);
	}
	while(q--){
		int l,r,ans=0;
		cin>>l>>r;
		if(l==r){
			cout<<0<<endl;
			continue;
		}
		int i=l-1;
		while(i<r){
			ans+=getsum(i+1,min(nxt[i]-1,r-1));//计算每一段的和
			i=nxt[i];//跳到下一段
		}
		cout<<ans<<endl;
	}
}
signed main(){
	cin.tie(0)->ios::sync_with_stdio(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
    //计算 c[i]
	for(int i=1;i<n;i++){
		if(a[i+1]>a[i]){
			int x=a[i];
			while(x*2<=a[i+1]){
				x*=2;
				c[i]--;
			}
		}else{
			int x=a[i+1];
			while(x<a[i]){
				x*=2;
				c[i]++;
			}
		}
	}
	for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i];//s[i]就是题解中的R[i]
	for(int i=1;i<=n;i++) ss[i]=ss[i-1]+c[i]*i;
	zj();
	return 0;
}