11.25 校内模拟赛总结

难评

复盘

7:40 开题

还是决定采取前期审题时间长一点的策略

T1,显然枚举斜率比较优,算一下复杂度是对的,就会了;T2 好神秘啊,感觉又是什么根据结论然后贪心删数;T3 显然是优化 dp,感觉可做;T4 嗯?这不是每日一题,按之前那个套路,把点分成一类点和二类点,直接放到线段树上维护合并就做完了?

感觉很稳啊,8:20 开码了

8:35 过了 T1 大样例,看 T2

手玩之后猜结论:贪心删能够被最早消完的。感觉很对,于是先写了指数暴力

然后写根据这个结论的做法,写完发现样例不过,一推发现假了

此时大概是 9:00,不急,写假做法的时候已经发现 i , j i,j i,j 固定时 s u m sum sum 是固定的,不关心前面的顺序,那么显然对于前面的部分可以 dp。继续想,只交换 i i i i + 1 i+1 i+1,影响应该比较小,那么拆成前缀和后缀,中间两个暴力合并,然而发现这样复杂度貌似还是三方,算了先写暴力,细节还挺多,写完就 9:40 了

写完后发现 dp 式子显然是格路,找到了一个十分简洁的转化:从 ( 0 , 0 ) (0,0) (0,0) 走到 ( n , n ) (n,n) (n,n),每个格子上有权值,一条路径权值为经过的格点的权值的 m a x + 1 max+1 max+1

基于这一点合并就变得十分简单了,每次只会改一列,枚举中间点在哪即可做到 n 2 n^2 n2,10:00 过了样例,然后开拍

接下来决定直接快速写完 T4,思路应该是比较清晰的

怒码 200 行,调了一小会,然后发现思路假了!我把限制转化成 j ≤ K + 1 − i j\leq K+1-i jK+1i,然后就忽略了 i < j i<j i<j 的限制;加上限制后每个点的合法决策是区间而不是前缀了,没法直接合并了

蚌,浪费 1h

只能完全换思路了,发现插数时好算贡献,删数时不好改贡献,那么上线段树分治,中间用线段树维护区间查 Max 就有 n log ⁡ 2 n\log ^2 nlog2 的做法, 5 × 1 0 5 5\times 10^5 5×105 说不定能过?

剩 1h 感觉不太写得完,还是看 T3

n 4 n^4 n4 很简单,然后想优化一维决策显然可以李超树做到 n 3 log ⁡ n^3\log n3log,感觉太唐了吧!推点性质

发现转移时好像只用枚举颜色就行,分别找到 a , b a,b a,b 中当前状态前面的第一个这种颜色转移就行,就 n 3 n^3 n3

先写,写着写着发现查每种颜色的 Max 显然可以拆成前缀和后缀用线段树直接维护,那就有 n 2 log ⁡ n^2\log n2log 了?不急,先写完

然后发现样例没过,再读题发现又读错了… … 他不能每次只迈左脚或者右脚,得一起迈

然后我的结论就直接假了,看时间已经 11:30 ,慌

思考了一下得到了一个差不多的结论:对于决策 ( p , q ) (p,q) (p,q),如果后面还有相同的颜色对 ( p ′ , q ′ ) (p',q') (p,q),那么 ( p , q ) (p,q) (p,q) 就是没用的

这显然说明了 随着 p p p 的增大, q q q 是单调不增的,双指针就能做到 n 3 n^3 n3

写了一会写破防了,发现细节很多,有一些边界问题

没办法,写 n 4 n^4 n4 吧,中间再加上一些玄学剪枝后能在 1.2 s 1.2s 1.2s 内跑出 n = 3000 n=3000 n=3000 的大样例,不过感觉没什么用

最后去写了 T 4 T4 T4 的暴力,差点不会 n 2 n^2 n2 了,还好最后想到了单调队列…

然后就结束了

结果是:

100 + 100 + 45 + 20 = 265 100+100+45+20=265 100+100+45+20=265

( 怎么大家 T1 都挂了 a

T3 运气好得到了 45 pts

T4 的决策很失误啊!明明有线段树分治的稳定得分 60pts ,没写简直亏麻了

总结来说这场看错题的情况太多了啊!感觉快一半时间都在编假做法、写假做法… …

题解

T2

在这里插入图片描述
感觉挺妙的,记录一下

格路在很多题还是有奇效的

T3

在这里插入图片描述
感觉这种优化 dp 应该是挺擅长的点的,但是我不会

首先编一个好看的 n 3 n^3 n3 做法,注意到 转移时枚举的两个决策是十分独立的!!! 我们考虑把决策分开来枚举,即:认为是先迈左脚,后迈右脚,加一维状态表示当前该迈哪只脚就能维护限制

就有转移:
在这里插入图片描述
拆开后显然是斜率优化板子,李超树 / 单调队列均可

#include<bits/stdc++.h>
using namespace std ;typedef long long LL ;
const int N = 3010 ;
// 分步转移!! int n , a[N] , b[N] ;
int f[N][N][2] ;
inline int D( int i , int j )
{return (j-i)*(j-i) ;
}
struct segment
{int K , B ;LL operator () ( int x ) { return K*x+B ; }
}tr[N*N*2] ;
struct Segtree
{int ls , rs ;
}t[N*N*2] ;
int rt[N][2] , tot ;
void Insert( int &p , int l , int r , segment L )
{if( !p ) {p = ++tot ; tr[p] = L ;return ;}int mid = (l+r)>>1 ;if( L(mid)<tr[p](mid) ) swap(L,tr[p]) ;if( L(l)<tr[p](l) ) Insert( t[p].ls , l , mid , L ) ;if( L(r)<tr[p](r) ) Insert( t[p].rs , mid+1 , r , L ) ;
}
int query( int p , int l , int r , int x )
{if( !p ) return 2e9 ;int mid = (l+r)>>1 , res = tr[p](x) ;if( x <= mid ) return min(res,query(t[p].ls,l,mid,x)) ;else return min(res,query(t[p].rs,mid+1,r,x)) ;
}int main()
{scanf("%d" , &n ) ;for(int i = 0 ; i <= n+1 ; i ++ ) {scanf("%d" , &a[i] ) ;}for(int i = 0 ; i <= n+1 ; i ++ ) {scanf("%d" , &b[i] ) ;}memset( f , 0x3f , sizeof f ) ;f[0][0][0] = 0 ;Insert(rt[0][0],0,n+1,{0,0}) ;for(int i = 0 ; i <= n+1 ; i ++ ) {for(int j = 0 ; j <= n+1 ; j ++ ) {if( i==0&&j==0 ) continue ;if( i ) f[i][j][1] = query(rt[j][0],0,n+1,i)+i*i ;if( a[i]==b[j] ) {if( j ) f[i][j][0] = query(rt[i][1],0,n+1,j)+j*j ;}if( f[i][j][0] < 1e9 ) Insert(rt[j][0],0,n+1,{-2*i,f[i][j][0]+i*i}) ;if( f[i][j][1] < 1e9 ) Insert(rt[i][1],0,n+1,{-2*j,f[i][j][1]+j*j}) ;}}printf("%d\n" , f[n+1][n+1][0] ) ;return 0 ;
}

T4

在这里插入图片描述
妙妙题

首先线段树分治显然可以 n log ⁡ 2 n\log^2 nlog2

还有感觉很牛的 n n n\sqrt n nn 做法:操作分块

把每 B B B 次操作放在一起处理,称这 B B B 次操作涉及到的位置为关键点

首先一遍单调队列处理出 非关键点内部的答案;对于关键点与非关键点之间,只需要维护每个关键点左右 k k k 个位置的最大值,单调队列维护即可;对于关键点之间,每次修改完后只对这 B B B 个位置单独跑单调队列

算一下复杂度是 n n n\sqrt n nn

感觉很高深,反正我想不到

然后说正解:

长度固定为 K K K,经典 trick 是每 K K K 个分成一段

来看这样做有什么好处:首先段内贡献显然可以直接维护区间 M a x , c M a x Max,cMax Max,cMax

对于段间,假设两段中选的位置分别是 i , j i,j i,j,我们 注意力惊人 的发现: i , j i,j i,j 中至少有一个是其所在段的最大值

简要证:不妨设 a i ≤ a j a_i\leq a_j aiaj,如果 i , j i,j i,j 都不是最大值,考虑把 i i i 换成 j j j 所在段的最大值,答案显然会更优

这样答案的情况被大大简化了,只需要考虑某个最大值和相邻段进行匹配即可

具体来说:

首先最终的答案用堆维护,把所有可能的答案放到堆里,查询时弹堆顶

段内,直接线段树查 M a x , c M a x Max,cMax Max,cMax,扔堆里;修改时直接维护

段间,找到当前段的最大值,查前面段的一段后缀,后面段的一段前缀,扔堆里;
修改时,受影响的只有 O ( 1 ) O(1) O(1) 个段内 M a x Max Max 的匹配情况,暴力更新即可

#include<bits/stdc++.h>
using namespace std ;typedef long long LL ;
const int N = 5e5+10 , inf = 1e9+10 ;
// 每 K 个分一段,分别考虑段内与相邻段间贡献
// 注意力惊人的发现对于段间贡献,必选某一段中的最大值,修改时的复杂度就降低了 int n , K , m , a[N] , bl[N] ;
int ans[N][3] ;
struct node
{int v , x , id ;friend bool operator < ( node a , node b ) {return a.v<b.v ;}
};
priority_queue<node> q ;
struct Segtree
{int l , r , Mx , id , Cx ;
}t[N<<2] ;
inline void update( int p ) 
{if( t[p<<1].Mx >= t[p<<1|1].Mx ) {t[p].Mx = t[p<<1].Mx ; t[p].id = t[p<<1].id ;t[p].Cx = max( t[p<<1|1].Mx , t[p<<1].Cx ) ;}else {t[p].Mx = t[p<<1|1].Mx ; t[p].id = t[p<<1|1].id ;t[p].Cx = max( t[p<<1].Mx , t[p<<1|1].Cx ) ;}
}
void build( int p , int l , int r )
{t[p].l = l , t[p].r = r , t[p].Mx = t[p].Cx = -1e9 ;if( l == r ) {t[p].Mx = a[l] , t[p].id = l ;return ;}int mid = (l+r)>>1 ;build(p<<1,l,mid) ; build(p<<1|1,mid+1,r) ;update(p) ;
}
Segtree query( int p , int l , int r )
{if( l <= t[p].l && t[p].r <= r ) {return t[p] ;}int mid = (t[p].l+t[p].r)>>1 ;if( l>mid ) return query(p<<1|1,l,r) ;if( r <= mid ) return query(p<<1,l,r) ;Segtree R1 = query(p<<1,l,r) , R2 = query(p<<1|1,l,r) ;if( R1.Mx>=R2.Mx ) {return {0,0,R1.Mx,R1.id,max(R1.Cx,R2.Mx)} ;}else {return {0,0,R2.Mx,R2.id,max(R1.Mx,R2.Cx)} ;}
}
void modify( int p , int x , int d )
{if( t[p].l==t[p].r ) {t[p].Mx = d ;return ;}int mid = (t[p].l+t[p].r)>>1 ;if( x <= mid ) modify(p<<1,x,d) ;else modify(p<<1|1,x,d) ;update(p) ;
}
void Rebuild( int i , int f )
{ans[i][f] = -inf ;int l = (i-1)*K+1 , r = min(i*K,n) ;Segtree R = query(1,l,r) ;if( f == 2 ) {if( r+1 <= min(n,R.id+K-1) ) ans[i][f] = query(1,r+1,min(n,R.id+K-1)).Mx+R.Mx ;}else {if( max(1,R.id-K+1) <= l-1 ) ans[i][f] = query(1,max(1,R.id-K+1),l-1).Mx+R.Mx ;}if( ans[i][f]!=-inf ) q.push({ans[i][f],i,f}) ;
}int main()
{scanf("%d%d%d" , &n , &K , &m ) ;for(int i = 1 ; i <= n ; i ++ ) {scanf("%d" , &a[i] ) ;bl[i] = (i-1)/K+1 ;}build(1,1,n) ;for(int i = 1 ; i <= n ; i += K ) {int r = min(n,i+K-1) ;Segtree R = query(1,i,r) ;ans[bl[i]][1] = R.Mx+R.Cx ;q.push({ans[bl[i]][1],bl[i],1}) ;ans[bl[i]][0] = -inf ;if( bl[i]!=1 ) {if( max(1,R.id-K+1) <= i-1 ) ans[bl[i]][0] = query(1,max(1,R.id-K+1),i-1).Mx+R.Mx ;}if( ans[bl[i]][0] != -inf ) q.push({ans[bl[i]][0],bl[i],0}) ;ans[bl[i]][2] = -inf ;if( bl[i]!=bl[n] ) {if( r+1 <= min(n,R.id+K-1) ) ans[bl[i]][2] = query(1,r+1,min(n,R.id+K-1)).Mx+R.Mx ;}if( ans[bl[i]][2] != -inf ) q.push({ans[bl[i]][2],bl[i],2}) ;}printf("%d\n" , q.top().v ) ;int x , v ;while( m -- ) {scanf("%d%d" , &x , &v ) ;a[x] = v ;modify(1,x,v) ;int l = (bl[x]-1)*K+1 , r = min(bl[x]*K,n) ;Segtree R = query(1,l,r) ;if( ans[bl[x]][1] != R.Mx+R.Cx ) {ans[bl[x]][1] = R.Mx+R.Cx ;q.push({ans[bl[x]][1],bl[x],1}) ;}if( bl[x]!=1 ) {ans[bl[x]][0] = -inf ;if( max(1,R.id-K+1) <= l-1 ) ans[bl[x]][0] = query(1,max(1,R.id-K+1),l-1).Mx+R.Mx ;if( ans[bl[x]][0] != -inf ) q.push({ans[bl[x]][0],bl[x],0}) ;Rebuild(bl[x]-1,2) ;}if( bl[x]!=bl[n] ) {ans[bl[x]][2] = -inf ;if( r+1 <= min(n,R.id+K-1) ) ans[bl[x]][2] = query(1,r+1,min(n,R.id+K-1)).Mx+R.Mx ;if( ans[bl[x]][2] != -inf ) q.push({ans[bl[x]][2],bl[x],2}) ;Rebuild(bl[x]+1,0) ;}while( 1 ) {int x = q.top().x , id = q.top().id ;if( ans[x][id] != q.top().v ) q.pop() ;else {printf("%d\n" , ans[x][id] ) ; 	break ;}}}return 0 ;
}

下面还有刚学到的 想象力惊人 的做法:

在这里插入图片描述
还是考虑段间贡献,本质是需要在两段中分别选出 i , j i,j i,j 使得 j − i + 1 ≤ K j-i+1\leq K ji+1K

移项,得 j ≤ K + i − 1 j\leq K+i-1 jK+i1,然后我们把 i i i 这一段按 K + i − 1 K+i-1 K+i1 重新排序

接下来把重排后的 i i i 这一段和 j j j 段放到一起,发现问题可以重新表述:

有序列 a , b a,b a,b,在 a a a 中选择 a i a_i ai,在 b b b 中选择 b j b_j bj 要求 i ≤ j i\leq j ij,使得 a i + b j a_i+b_j ai+bj 最大

然后直接套赛时那个本来会假的思路就行了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习编程,学习中间件,学习源码的思路

01 看的多&#xff0c;内化不足 最近想复习一下编程相关的知识&#xff0c;在复习前我翻开了之前的一些笔记&#xff0c;这些笔记基本都是从书本、视频、博客等摘取记录的&#xff0c;看着这些笔记心里总结&#xff1a;看的多&#xff0c;内化不足。 02 整理大纲 为了解决这个…

[C++]vector:迭代器失效和vector<string>中更深层次拷贝的问题

迭代器失效 一、迭代器失效的两大类型异地扩容后的失效原地删除后的失效 二、vector<string>出现的深层次拷贝问题 一、迭代器失效的两大类型 异地扩容后的失效 在vector容器中&#xff0c;通常情况下的扩容都是异地扩容&#xff0c;例如resize, reserve&#xff0c;但…

初识 Django

声明 适用于想要快速入门的开发者&#xff0c;有前后端开发以及语言基础&#xff0c;想要学习语法或者特性。 想要学会快速开发&#xff0c;快速入门&#xff0c;请看博客【实用向】Django 框架入门并结合本篇文章。 命令 命令描述startproject创建一个 Django 项目startapp…

.net core MVC入门(一)

文章目录 项目地址一、环境配置1.1 安装EF core需要包1.2 配置数据库连接二、使用EF创建表2.1 整体流程梳理2.1 建表详细流程三、添加第一个视图3.1整体流程梳理3.1 添加视图,并显示在web里四、使用EF增加Catogory数据,并且读取数据到页面4.1整体流程梳理4.2 实现五、增加Cat…

【freertos】FreeRTOS消息队列的介绍与使用

FreeRTOS消息队列的介绍与使用 一、概述二、消息队列的运作机制三、API函数1、消息队列创建函数2、消息队列静态创建函数3、用于向队列尾部发送一个队列消息4、在中断服务程序中用于向队列尾部发送一个消息5、向队列队首发送一个消息6、在中断服务程序中向消息队列队首发送一个…

页的初步认识

关于准备 我们在之前的学习中&#xff0c;已经学习了相当一部分有关段的知识&#xff0c;CPU提供了段的机制来给我们的内存进行保护&#xff0c;但实际上我们在x86下的段base是0&#xff0c;实际上并没有偏移 两种分页模式 我们有两种分页模式&#xff0c;29912分页和101012…

题目一:bugku---game1

2024.11.21 1、题目连接&#xff1a; 2、打开是个小游戏 3、正常玩一把结束后&#xff0c;用bp抓包 4、查看url有三个参数&#xff0c;score对应的就是我们结束这把游戏时获得的分数&#xff0c;sign的zM后面为这把游戏分数的base64加密 5、将抓到的包&#xff0c;发送到重放…

小柴冲刺软考中级嵌入式系统设计师系列三、嵌入式硬件设计(1)嵌入式系统电源管理

越努力&#xff0c;越幸运&#xff01; 人生的意义在于体验&#xff01; 目录 越努力&#xff0c;越幸运&#xff01; 一、电源管理 (1)系统上电行为 (2)空闲模式 (3)断电 (4)电压与频率缩放 例如 具体实现如下: ① 12V 转8V ② 12V 转-8V ③ 12V 转5V ④ 5V 转3…

C++ 优先算法 —— 长度最小的子数组(滑动窗口)

目录 题目&#xff1a;长度最小的子数组 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 滑动窗口正确性 3. 代码实现 Ⅰ. 暴力枚举(会超时&#xff09; Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 题目&#xff1a;长…

uniapp定义new plus.nativeObj.View实现APP端全局弹窗

为什么要用new plus.nativeObj.View在APP端实现弹窗&#xff1f;因为uni.showModal在APP端太难看了。 AppPopupView弹窗函数参数定义 参数一:弹窗信息(所有属性可不填&#xff0c;会有默认值) 1.title:"", //标题 2.content:"", //内容 3.confirmBoxCo…

网络安全——SpringBoot配置文件明文加密

一、前言 在日常开发中&#xff0c;项目中会有很多配置文件。比如SpringBoot项目核心的数据库配置、Redis账号密码配置都在properties、yml配置文件 中。 如果这些信息以明文的方式存储&#xff0c;你的电脑被拿去修理&#xff0c;就会容易泄露&#xff0c;一旦被其他人获取到…

Linux系统编程之进程基础知识

概述 在Linux系统中&#xff0c;进程是指一个正在运行的程序实例。每个进程都有一个唯一的进程标识符&#xff0c;即PID&#xff0c;操作系统通过这个PID来唯一识别和管理各个进程。进程不仅仅是程序代码的运行实例&#xff0c;它还包含了程序运行时所需的各种资源&#xff0c;…

2024智能机器人与自动控制国际学术会议 (IRAC 2024)

主办&#xff0c;承办&#xff0c;支持单位 会议官网 www.icirac.org 大会时间&#xff1a;2024年11月29-12月1日 大会简介 2024智能机器人与自动控制国际学术会议 &#xff08;IRAC 2024&#xff09;由华南理工大学主办&#xff0c;会议将于2024年11月29日-12月1日在中国广…

【Pytest+Yaml+Allure】实现接口自动化测试框架

一、框架思想 requestsyamlpytestallure实现接口自动化框架。结合数据驱动和分层思想&#xff0c;将代码与数据分离&#xff0c;易维护&#xff0c;易上手。使用yaml编写编写测试用例&#xff0c;利用requests库发送请求&#xff0c;使用pytest管理用例&#xff0c;allure生成…

利用 Jsoup 进行高效 Web 抓取与 HTML 处理

Jsoup 是一款 Java 的 HTML 解析器&#xff0c;可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API&#xff0c;可通过 DOM&#xff0c;CSS 以及类似于 JQuery 的操作方法来取出和操作数据。 官网&#xff1a;https://jsoup.org/ 中文文档&#xff1a;Jsou…

蓝桥杯不知道叫什么题目

小蓝有一个整数&#xff0c;初始值为1&#xff0c;他可以花费一些代价对这个整数进行变换。 小蓝可以花贵1的代价将教数增加1。 小蓝可以花费3的代价将整数增加一个值,这个值是整数的数位中最大的那个(1到9) .小蓝可以花费10的代价将整数变为原来的2倍, 例如&#xff0c;如果整…

【JavaEE初阶】枫叶经霜艳,梅花透雪香-计算机是如何运行的?

本篇博客给大家带来的是与计算机相关的知识点, 包括:计算机的组成, 指令, 进程(重点). 文章专栏: JavaEE初阶 若有问题 评论区见 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 1. 计算机的组成 1.1 计算机的发展史 计算…

SuperMap Objects组件式GIS开发技术浅析

引言 随着GIS应用领域的扩展&#xff0c;GIS开发工作日显重要。一般地&#xff0c;从平台和模式上划分&#xff0c;GIS二次开发主要有三种实现方式&#xff1a;独立开发、单纯二次开发和集成二次开发。上述的GIS应用开发方式各有利弊&#xff0c;其中集成二次开发既可以充分利…

Linux网络——NAT/代理服务器

一.NAT技术 1.NAT IP转换 之前我们讨论了, IPv4 协议中, IP 地址数量不充足的问题&#xff0c;NAT 技术就是当前解决 IP 地址不够用的主要手段, 是路由器的一个重要功能。 NAT 能够将私有 IP 对外通信时转为全局 IP. 也就是一种将私有 IP 和全局IP 相互转化的技术方法: 很…

使用八爪鱼爬虫抓取汽车网站数据,分析舆情数据

我是做汽车行业的&#xff0c;可以用八爪鱼爬虫抓取汽车之家和微博上的汽车文章内容&#xff0c;分析各种电动汽车口碑数据。 之前&#xff0c;我写过很多Python网络爬虫的案例&#xff0c;使用requests、selenium等技术采集数据&#xff0c;这次尝试去采集小米SU7在微博、汽车…