啊?

news/2025/11/10 18:42:32/文章来源:https://www.cnblogs.com/FloatingLife/p/19207366

日常花絮,不建议当题解看。

事情的起因是模拟赛考了这么一道题:

他放在了 T2,我也场切了,所以我觉得这就是个简单贪心题。但是赛后讲评人说这个题等价于 NOIP2023 T3,由于我不太相信自己能场切紫题(虽然洛谷日常虚高),且我前年赛时以及去年和今年 VP 的时候都尝试过双序列拓展,但是都失败了,也没有看过题解,所以我觉得我不可能因为他放在 T2 就切出了我尝试 \(3\) 次都不会的题。


先讲一下这个模拟赛题的做法:
题意转换一下,把 \(a\) 序列用前缀和替代,条件等价于 \(a_l\ge a_r\),那么可以把 \(a[1,k]\) 当成一个序列 \(x\)\(reverse(a[k,n])\) 当成一个序列 \(y\),现在假设 \(n,m\) 分别为序列 \(x,y\) 的长度,且维护两个指针 \(l,r\) 初始 \(l=r=1\),每次可以移动一个指针且需要始终满足 \(x_l\ge y_r\),问是否能最终让 \(l=n,r=m\)
首先有一些显然无解的情况:\(x_1<y_1,x_n<y_m,\max(x_i)<\max(y_i),\min(x_i)<\min(y_i)\)。下面认为不会出现这 \(4\) 种情况。

一个想法是贪心地在 \(r=1\) 时让 \(l\) 尽可能往右移,直到遇到一个 \(x_u<y_r\),此时 \(x_u\) 不能再和 \(x_r\) 匹配了,因此我们需要在之前的某个 \(l=i<u\) 的时刻,把 \(r\) 往右移到一个满足 \(y_v\le x_u\) 的地方,这样才能让 \(l\) 顺利度过 \(u\) 这个地方。显然这个 \(i\) 我们会选择 \(x[1,u)\) 中最大值的位置(这样 \(r\) 能移得次数最多),这个 \(v\) 我们会选择 \(x_i\) 能让 \(r\) 移动的范围内(即移动 \(r\) 的过程中不能出现 \(y_r>x_i\) 的情况)最小值的位置。如果找不到这样的 \(v\) 显然无解,否则让 \(l=u,r=v\),继续重复这个过程。
但是有个问题,虽然我们最后可以让 \(l=n\),但是 \(r\) 不一定可以到 \(m\),事实上,最后我们至多只会把 \(r\) 移动到 \(y\) 的全局最小值的位置上,因为假设 \(pos_1\)\(x\) 的全局最大值的位置,\(pos_2\)\(y\) 的全局最小值的位置,那么在上面的过程中当 \(pos_1<u\) 时,\(i,v\) 分别会取到 \(pos_1,pos_2\),然后我们就会一口气把 \(l\) 移到 \(n\);即使没有出现过 \(pos_1<u\) 的情况,我们也可以在 \(l=pos_1\) 时立刻把 \(r\) 移到 \(pos_2\),这样也一定是合法的。
那怎么办呢,发现指针的移动是可逆的,所以直接把序列 \(x,y\)\(reverse\) 一下再做一遍,如果 \(r\) 仍然能到全局最小值的位置那么就是合法的。
当然为了方便的话,你可以只对 \(x[1,pos_1],y[1,pos_2]\)\(reverse(x[pos_1,n]),reverse(y[pos_2,m])\) 分别做一遍,看一下每次 \(r\) 是否能移到最后即可。
不难用双指针维护这个过程,复杂度线性。

贴个代码:

#include<bits/stdc++.h>
#define Debug puts("-------------------------")
#define LL long long 
using namespace std;
const int N=1e5+5;
template <typename T>
inline void read(T &x){T w=1,s=0;char c=getchar();for(;c<'0'||c>'9';w*=(c=='-')?-1:1,c=getchar());for(;c>='0'&&c<='9';s=s*10+c-'0',c=getchar());return x=w*s,void();
}
int T,n,k;
LL a[N],b[N],c[N];
bool check(int n,int m){int now=1,pos=0;LL maxn=LLONG_MIN,ming=LLONG_MAX;for(int i=1,j=1;i<=n;i++){if(b[i]<c[now]){while(j<=m&&c[j]<=maxn){if(c[j]<ming) ming=c[j],pos=j;j++;}now=pos;if(b[i]<c[now]) return false;}else maxn=max(maxn,b[i]);}return true;
}
signed main(){double beg=clock();read(T);while(T--){read(n),read(k);LL mx1=LLONG_MIN,mx2=LLONG_MIN,mn1=LLONG_MAX,mn2=LLONG_MAX;for(int i=1;i<=n;i++){read(a[i]);a[i]+=a[i-1];if(i<=k) mx1=max(mx1,a[i]),mn1=min(mn1,a[i]);if(i>=k) mx2=max(mx2,a[i]),mn2=min(mn2,a[i]);}if(a[1]<a[n]||mx1<mx2||mn1<mn2){puts("No");continue;}int pos1=0,pos2=0;for(int i=1;i<=k;i++) if(a[i]==mx1){ pos1=i; break; }for(int i=k;i<=n;i++) if(a[i]==mn2){ pos2=i; break; }for(int i=1;i<=pos1;i++) b[i]=a[i];for(int i=n,j=1;i>=pos2;i--,j++) c[j]=a[i];bool flag=check(pos1,n-pos2+1);if(!flag){puts("No");continue;} for(int i=k,j=1;i>=pos1;i--,j++) b[j]=a[i];for(int i=k,j=1;i<=pos2;i++,j++) c[j]=a[i];flag=check(k-pos1+1,pos2-k+1);puts(flag?"Yes":"No");}cerr << "Time: " << (clock()-beg) << endl;return 0;
}

我赛时的另一个思考方向是,相当于要对 \(x\) 序列的每个 \(x_i\) 分配一个区间 \([L_i,R_i]\),满足 \(\forall j\in [L_i,R_i],y_j\le x_i\),且 \(L_1=1,R_n=m,L_i=R_{i-1}\)。直接做可以 \(O(n^2)\),可惜我并没有想到优化的办法。但是这个思路在下面会用到。


将信将疑之下,我再次打开双序列序列拓展,根据题意把代码改了一下(唯二的区别是双序列拓展的条件不含 \(=\),且可以是全 \(>\),也可以是全 \(<\),不过也就是取负之后做两遍而已):

#include<bits/stdc++.h>
#define Debug puts("-------------------------")
using namespace std;
const int N=5e5+5;
template <typename T>
inline void read(T &x){T w=1,s=0;char c=getchar();for(;c<'0'||c>'9';w*=(c=='-')?-1:1,c=getchar());for(;c>='0'&&c<='9';s=s*10+c-'0',c=getchar());return x=w*s,void();
}
int test_id,n,m,T;
int t1[N],t2[N],x[N],y[N],b[N],c[N];
bool check(int n,int m){int now=1,pos=0;int maxn=INT_MIN,ming=INT_MAX;for(int i=1,j=1;i<=n;i++){if(b[i]<=c[now]){while(j<=m&&c[j]<maxn){if(c[j]<ming) ming=c[j],pos=j;j++;}now=pos;if(b[i]<=c[now]) return false;}else maxn=max(maxn,b[i]);}return true;
}
bool work(){int mx1=INT_MIN,mx2=INT_MIN,mn1=INT_MAX,mn2=INT_MAX;for(int i=1;i<=n;i++) mx1=max(mx1,x[i]),mn1=min(mn1,x[i]);for(int i=1;i<=m;i++) mx2=max(mx2,y[i]),mn2=min(mn2,y[i]);if(x[1]<=y[1]||x[n]<=y[m]||mx1<=mx2||mn1<=mn2) return false;int pos1=0,pos2=0;for(int i=1;i<=n;i++) if(x[i]==mx1){ pos1=i; break; }for(int i=1;i<=m;i++) if(y[i]==mn2){ pos2=i; break; }for(int i=1;i<=pos1;i++) b[i]=x[i];for(int i=1;i<=pos2;i++) c[i]=y[i];if(!check(pos1,pos2)) return false;for(int i=n,j=1;i>=pos1;i--,j++) b[j]=x[i];for(int i=m,j=1;i>=pos2;i--,j++) c[j]=y[i];return check(n-pos1+1,m-pos2+1);
}
bool solve(){bool flag=work();for(int i=1;i<=n;i++) x[i]=-x[i];for(int i=1;i<=m;i++) y[i]=-y[i];flag|=work();return flag; 
}
signed main(){double beg=clock();scanf("%d%d%d%d",&test_id,&n,&m,&T);for(int i=1;i<=n;i++) scanf("%d",&t1[i]),x[i]=t1[i];for(int i=1;i<=m;i++) scanf("%d",&t2[i]),y[i]=t2[i];string ans="";ans=ans+(solve()?'1':'0');while(T--){int kx,ky; scanf("%d%d",&kx,&ky);memcpy(x,t1,sizeof x),memcpy(y,t2,sizeof y);for(int i=1,p,v;i<=kx;i++){scanf("%d%d",&p,&v);x[p]=v;}for(int i=1,p,v;i<=ky;i++){scanf("%d%d",&p,&v);y[p]=v;}	ans=ans+(solve()?'1':'0');}cout<<ans<<'\n';cerr << "Time: " << (clock()-beg) << endl;return 0;
}

可以发现核心代码 check 函数完全没有变,但是他过了。

同样转换一下题意发现双序列拓展等价于:
\(x\) 序列的每个 \(x_i\) 分配一个区间 \([L_i,R_i]\),满足 \(\forall j\in [L_i,R_i],y_j< x_i\),且 \(L_1=1,R_n=m,L_i=R_{i-1} or R_{i-1}+1\)
举个例子,对于 \(x=\{ 3,2,4,2 \},y=\{ 2,1,3,1 \}\),显然可以让 \(L_i=R_i=i\),但这在上一题是不允许的。

但显然正赛数据不可能这么水,所以仔细思考后发现这两个题其实真的是等价的:

  • 充分性:上一题合法的构造方案放到这一题显然是合法的。
  • 必要性:我们要证明这一题合法的构造方案一定可以转换成上一题合法的构造方案,若存在 \(i,i+1\) 满足 \(R_i+1=L_{i+1}\),那么如果 \(x_i<x_{i+1}\) 则可以把 \(L_{i+1}-1\),否则可以把 \(R_i+1\)

看了题解之后发现大家好像都是转换成网格图走路的,但是代码实现出来本质貌似是一样的。

所以考场上我该如何想到双序列拓展这个题实际上不需要考虑 \(R_i+1=L_{i+1}\) 的情况。

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

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

相关文章

Docker部署FileBrowser轻量网盘

本文在Ubuntu和威联通NAS演示了Docker部署FileBrowser轻量网盘的方法官网:Installation - File Browser filebrowser 是一款非常优秀的文件管理工具,并且是跨平台。安装也非常简单,安装后就可以使用,同样使用也非常…

2025/11/10~2025/11/16 做题笔记 - sb

2025/11/10 C. 圆环(circle) 感觉比 T2 要简单/kk dp 状态是好想的,非常明显可以设 \(f_{i, j}\) 表示当操作完 \(i\) 操作,另一只手在 \(j\) 位置的最小代价。这个东西的状态转移方程也不难。当由不是完成操作的手…

校园二手物品交易平台

校园二手物品交易平台——Java面向对象课程设计方案 组员名单:薛朝建、陈博凯、陈炤辉 一、AI工具辅助选题历程 在Java面向对象课程设计的选题阶段,我们借助多款AI工具提升决策效率:核心使用DeepSeek大模型开展选题…

pytorch、torchaudio、torchvideo版本对应关系

PyTorch版本 torchvision版本 torchaudio版本 2.5.0 0.20.0 2.5.0 2.4.1 0.19.1 2.4.1 2.4.0 0.19.0 2.4.0 2.2.1 0.17.1 2.2.1 2.2.0 0.17.0 2.2.0 2.1.0 0.16.0 2.1.0 …

【四级】全国大学英语四级历年真题及答案解析PDF电子版(2015-2025年6月) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

OpenGL进化史:从实验室到现代图形革命的里程碑之旅

OpenGL进化史:从实验室到现代图形革命的里程碑之旅 引言:为什么我们需要了解OpenGL的历史? OpenGL(Open Graphics Library)是计算机图形学的基石之一,驱动了从游戏到AI可视化、从虚拟现实到电影特效的无数创新。…

提示词语料收集

先开始收集常用的,不做分类,后期多了再分类处理 1、你是个XXXX,我是个菜鸟,用我能明白的方式向我解释一下YYY2、你个xxx,为我设计个yyy系统,并提供详细的编码实现与目录结构,完成设计后对你的设计进行评分,1分…

新手做幼儿园营养食谱公众号在哪找好看的素材?

如果你刚开始做幼儿园营养食谱的公众号,肯定会为找素材和排版发愁。其实,用对小工具就简单多了,比如小墨鹰编辑器,里面就有很多适合这个主题的素材。 第一步:先定一个“可爱又开胃”的基调在小墨鹰的模板中心,你…

C语言中的数据存储

1.数据类型 c语言自带的一些数据类型 char //字符型 1byte short //短整型 2byte int //整型 4byte long //长整型 4 or 8byte long long //更长的整型 8byte float…

咋提宣讲

不妨假设先手放在 \(1\) 号点,最后对每个点都做一遍即可。 \(N = 2\) 的时候先手必胜当且仅当 \(A_1 > A_2\)。 再难一点,\(1\) 的度数为 \(N - 1\) 时,考虑所有儿子的 \(A_i\) 的 \(\min\) 为 \(minn\),如果 \…

20232428 2025-2026-1 《网络与系统攻防技术》实验四实验报告

实验内容 一、恶意代码文件类型标识、脱壳与字符串提取 对提供的rada恶意代码样本,进行文件类型识别,脱壳与字符串提取,以获得rada恶意代码的编写作者,具体操作如下: (1)使用文件格式和类型识别工具,给出rada恶…

【模板】ccpc板子库

字符串 KMP #include<bits/stdc++.h> #define N 1000010 #define fo(a, b, c) for(int b = a; b <= c; b++) using namespace std; int n, m, b[N]; string s, t; int main(){ios::sync_with_stdio(0);cin.t…

20232428 2025-2026-1 《网络与系统攻防技术》实验三实验报告

1.实验内容 实践内容 (1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧 正确使用msf编码器,使用msfvenom生成如jar之类的其他文件 veil,加壳工具 使用C + shellcode编程 (2)通过组合应用…

详细介绍:P3375 【模板】KMP

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

11月10号

今天进行了统一建模和数据结构的学习。 然后就进行了java中数据库和服务器的学习。

基于DP1323EL的电动车解锁方案:超高速读写,提升电动车一键解锁体验

电动车无钥匙解锁 在快节奏的都市生活中,电动车已成为许多人的首选出行工具。然而,传统的机械钥匙往往带来诸多不便:容易丢失、操作繁琐,甚至在雨天或匆忙时成为负担。 随着物联网和智能科技的快速发展,一键解…

最强LLM生成代码也会出错?

最强LLM生成代码也会出错?背景 大语言模型(LLM)在代码生成方面无疑取得了惊人的进步,早已成为许多开发者不可或缺的日常工具。从自动补全到生成完整函数,AI正在重塑软件开发的生态。但当这些先进的AI模型生成…

张量与向量

这个问题抓得很准,核心结论是:向量是张量的特殊形式(1维张量),张量是向量的“高维扩展”,二者是“特殊与一般”的关系,核心区别在于维度和数据承载能力。 ### 1. 定义与维度差异 - **向量**:严格来说是1维张量…