题解:P5226([SCOI2015] 小凸解密码)

news/2025/11/28 9:41:14/文章来源:https://www.cnblogs.com/ChenMuJiu/p/19280355

1. Description

小凸得到了一个密码盘,密码盘被等分成 \(n\) 个扇形,每个扇形上有一个数字 \((0 \sim 9)\),和一个符号 \((\) + 或 * \()\)。密码盘解密的方法如下:

首先,选择一个位置开始,顺时针地将数字和符号分别记在数组 \(A\) 和数组 \(C\) 中。解密的方法如下:

  • \(B_0 = A_0\)
  • \(x > 0\) 时:
    • \(C_x\) 为 +,\(B_x = (A_x + A_{x - 1}) \bmod 10\)
    • \(C_x\) 为 *,\(B_x = (A_x \times A_{x - 1}) \bmod 10\)

操作完成后,可以得到一个长度为 \(n\) 的数组 \(B\),然后以 \(B_0\) 为起点将 \(B\) 数组顺时针写成一个环,解密就完成了,称得到的环为答案环。

现在小凸得到了一份指令表,指令表上有 2 种操作。一种指令是修改操作,即改变原来密码盘上一个位置的数字和符号。另一种指令是询问操作,具体如下:

  • 首先从指令给出的位置开始完成解密,得到答案环。
  • 答案环上会有一些 \(0\) 连在一起,将这些连在一起的 \(0\) 称为零区间,找出其中距离 \(B_0\) 最远的那个零区间,输出这个距离(零区间和 \(B_0\) 的距离定义为:零区间内所有 \(0\)\(B_0\) 距离中的最小值)。

2. Solution

首先不妨来思考这道题的简化版,就是每一次询问的起始位置都是 \(0\)

想到对于一个零区间 \((l,r)\),它到 \(0\) 的距离为 \(\min(l,n-r)\),所以可以尝试维护起始位置为 \(0\) 的所有零区间 \((l,r)\)

而对于一个修改,最多只会修改 \(x\)\(x+1\) 两个位置的值,所以维护起来是简单的,这里不过多赘述了,具体实现可以看代码。

对于询问,我们不难想到去除 \(\min\),因此将所有区间分为三类:

  1. \(l,r\in[0,\frac{n}{2}]\),距离为 \(l\)
  2. \(l,r\in [\frac{n}{2}+1,n-1]\),距离为 \(n-r\)
  3. \(l\in [0,\frac{n}{2}],r\in [\frac{n}{2}+1,n-1]\),距离为 \(\min(l,n-r)\)

因为所有零区间不会有交,所以第三类的区间最多只有一个,特判即可。

对于第一类区间,我们需要求出 \(l\) 最大的区间,对于第二类区间,我们需要求出 \(r\) 最小的区间,所以可以使用一个 set 维护所有零区间,然后二分查找出对应区间即可。

然后考虑起始位置不一致的情况,令起始位置为 \(pos\)

此时 \(pos\)\(0\) 的值会发生变化,并且如果存在两个区间 \((x,n-1)\)\((0,y)\),它们实际上应该并成同一个区间 \((x,y)\),如果存在一个区间 \((x,y)\) 包含 \(pos\),它实际上应该被分成两个区间 \((x,pos-1)\)\((pos,y)\)

然后所以区间应该被分成如下三类:

  1. \(l,r\in [pos,pos+\frac{n}{2}]\)
  2. \(l,r\in [pos+\frac{n}{2}+1,pos+n-1]\)
  3. \(l\in [pos,pos+\frac{n}{2}],r\in[pos+\frac{n}{2}+1,pos+n-1]\)

最后注意一下分类讨论,求解即可,代码中有详细的注释,可供参考。

3. Code

#include<bits/stdc++.h>
#define pii pair<int,int>
#define Name 838412064
#define raed(x) read(x)
#define Nxt puts("")
#define Spa putchar(32)
#define Pline puts("------------------------------")
namespace FastIO{int write_top,read_f,read_x;char read_char;int write_st[20];inline int read(int &a){read_char=getchar();read_f=1;a=0;while(!isdigit(read_char)){if(read_char=='-')read_f=-1;read_char=getchar();}while(isdigit(read_char)){a=(a<<1)+(a<<3)+(read_char^48);read_char=getchar();}return a=a*read_f;}inline int read(){read_char=getchar();read_f=1;read_x=0;while(!isdigit(read_char)){if(read_char=='-')read_f=-1;read_char=getchar();}while(isdigit(read_char)){read_x=(read_x<<1)+(read_x<<3)+(read_char^48);read_char=getchar();}return read_x*read_f;}inline void write(int x){if(x<0)putchar('-'),x=-x;write_top=0;do{write_st[++write_top]=x%10;x/=10;}while(x);while(write_top)putchar(write_st[write_top--]+'0');return ;}inline void tomax(int &a,int b){if(a<b)a=b;return ;}inline void tomin(int &a,int b){if(a>b)a=b;return ;}
}
using namespace FastIO;
using namespace std;
const int N=1e5+5;
int n,m,half;
int A[N],B[N];
char C[N];
set<pii>st;
struct Node{pii a,b,c;bool opt;
}Mod[5];
void change(int x,int val){//将 B_x 设为 val if(B[x]==0){//B_x 本来是 0,将区间分成 (l,x-1),(x+1,r) auto it=st.upper_bound({x,n});auto tmp=*(--it);st.erase(it); if(tmp.first<x)st.insert({tmp.first,x-1});if(x<tmp.second)st.insert({x+1,tmp.second});}B[x]=val;if(B[x]==0){//B_x 修改之后是 0,尝试合并两边的区间 auto it=st.insert({x,x}).first;int nowl=x,nowr=x;if(next(it)!=st.end()){auto tmp=*next(it);if(tmp.first==x+1){st.erase(it);st.erase(tmp);it=st.insert({nowl,tmp.second}).first;nowr=tmp.second;}}if(it!=st.begin()){auto tmp=*prev(it);if(tmp.second==x-1){st.erase(it);st.erase(tmp);it=st.insert({tmp.first,nowr}).first;nowl=tmp.first;}}}
}
void modify(int x){//要修改 x 和 x+1 的值  int num;char opt;read(num),opt=getchar();while(opt!='+'&&opt!='*')opt=getchar();A[x]=num,C[x]=opt;int val;if(x==0)val=A[0];else val=(C[x]=='+'?A[x]+A[x-1]:A[x]*A[x-1])%10;change(x,val);if(x!=n-1){val=(C[x+1]=='+'?A[x+1]+A[x]:A[x+1]*A[x])%10;change(x+1,val);}
}
int dist(int x,int y){//求之间两个位置的距离 if(x==y)return 0;if(x<y)return min(y-x,n+x-y);return min(x-y,n+y-x);
}
int query(int x){if(x==0){//起始位置为 0 的特判 if(st.size()==0)//没有零区间,答案为 0 return -1;if(st.size()==1)//只有一个零区间,可以直接算  return min(dist(0,st.begin()->first),dist(0,st.begin()->second));int res=-1;/*将区间分为三类 1.l,r\in [0,half]2.l,r\in [half+1,n-1]2.l\in [0,half],r\in [half+1,n-1]*///求第一类 + 第三类   auto it=st.upper_bound({half,n});//所有满足 l<=half 的 (l,r) 都比 (half,n) 小//所以 it 的前一个就是第一类的最后一个区间(或者是第三类的区间)  if(it!=st.begin()){it--;if(it->second>half){//由于 r > half,所以这是第三类区间  tomax(res,min(dist(0,it->first),dist(0,it->second)));if(it!=st.begin()){it--;//由于第三类区间只有一个,所以这个肯定是第一类的区间了  tomax(res,dist(0,it->first));}}else tomax(res,dist(0,it->first));//否则这个就是第一类的区间  } //求第二类  it=st.upper_bound({half,n});//所有满足 l>half 的 (l,r) 都比 (half,n) 大//所以 it 就是第二类的第一个  if(it!=st.end())tomax(res,dist(x,it->second));return res;}//修改 0 和 x 位置的值  change(0,(C[0]=='+'?A[0]+A[n-1]:A[0]*A[n-1])%10);change(x,A[x]);int cnt=0;if(B[x]==0){//将包含 x 的区间分开  auto it=st.upper_bound({x,n});//求出 l>x 的第一个区间,前一个就是包含 x 的区间  it--;if(it->first!=x){cnt++;//记录修改方便最后撤销  Mod[cnt].opt=1;Mod[cnt].a=*it;Mod[cnt].b={it->first,x-1};Mod[cnt].c={x,it->second};st.erase(it);st.insert(Mod[cnt].b);st.insert(Mod[cnt].c);	}}if(B[0]==0){//将 (x,n-1) (0,y) 合并为 (x,y) if(st.rbegin()->second==n-1){//要满足右端点为 n-1 cnt++;Mod[cnt].opt=0;Mod[cnt].a=*st.rbegin();Mod[cnt].b=*st.begin();Mod[cnt].c={Mod[cnt].a.first,Mod[cnt].b.second};st.erase(*st.rbegin());st.erase(*st.begin());st.insert(Mod[cnt].c);}}	//下面两个特判和 x=0 时是一样的  if(st.size()==1){int res=min(dist(x,st.begin()->first),dist(x,st.begin()->second));//注意撤销的先后顺序,要从后往前撤销 for(int j=cnt;j>=1;j--){ if(Mod[j].opt==1){st.erase(Mod[j].b);st.erase(Mod[j].c);st.insert(Mod[j].a);}else{st.erase(Mod[j].c);st.insert(Mod[j].a);st.insert(Mod[j].b);}}change(0,A[0]);change(x,(C[x]=='+'?A[x]+A[x-1]:A[x]*A[x-1])%10);return res;}if(st.size()==0){for(int j=cnt;j>=1;j--){if(Mod[j].opt==1){st.erase(Mod[j].b);st.erase(Mod[j].c);st.insert(Mod[j].a);}else{st.erase(Mod[j].c);st.insert(Mod[j].a);st.insert(Mod[j].b);}}change(0,A[0]);change(x,(C[x]=='+'?A[x]+A[x-1]:A[x]*A[x-1])%10);return -1;}int res=-1;if(x+half<n){/*区间分为三类 1. l,r\in [x,x+half]2. l,r\in [x+half,n-1] and [0,x-1]3. l\in [x,x+half] r\in [x+half,n-1] and [0,x-1]*///求第一类 + 第三类 auto it=st.upper_bound({x+half,n});if(it!=st.begin()){it--;if(it->first>=x){if(it->second>x+half||it->second<x){//是第三类区间  tomax(res,min(dist(x,it->first),dist(x,it->second)));if(it!=st.begin()){it--;//同理,向前一个必定是第一类区间  if(it->first>=x)tomax(res,dist(x,it->first));}}else tomax(res,dist(x,it->first));	}}//求第二类  it=st.upper_bound({x+half,n});if(it!=st.end())tomax(res,dist(x,it->second));else if(st.begin()->first<x)tomax(res,dist(x,st.begin()->second));//如果这个区间是 (l,r) r>=x 的话,这个区间应该被分成两个//所以这个区间必然是第二类的区间 }else{/*区间分为三类 1. l,r\in [x,n-1] and [0,x+half-n]2. l,r\in [x+half-n+1,x-1]3. l\in [x,n-1] and [0,x+half-n] r\in [x+half-n+1,x-1]*/auto it=st.upper_bound({x+half-n,n});if(it!=st.begin()){it--;if(x+half-n<it->second&&it->second<x){//是第三类的区间  tomax(res,min(dist(x,it->first),dist(x,it->second)));if(it!=st.begin()){//如果不是第一个的话,第一类的最后一个就是它的前一个  it--;tomax(res,dist(x,it->first));}else{//否则,就是最后一个  it=st.end();it--;if(it->first>=x)//注意判断是否合法  tomax(res,dist(x,it->first));}}else tomax(res,dist(x,it->first));//否则就是这个  }else{//这里同理,应该是最后一个 it=st.end();it--;if(it->first>=x){//同样判断是否合法 //这里跟前面类似  if(x+half-n<it->second&&it->second<x){tomax(res,min(dist(x,it->first),dist(x,it->second)));if(it!=st.begin()){it--;if(it->first>=x)tomax(res,dist(x,it->first));}}else tomax(res,dist(x,it->first));}}//求第二类  it=st.upper_bound({x+half-n,n});if(it!=st.end())if(it->second<x)//注意是否合法  tomax(res,dist(x,it->second));}	//同样要从后往前撤销  for(int j=cnt;j>=1;j--){if(Mod[j].opt==1){st.erase(Mod[j].b);st.erase(Mod[j].c);st.insert(Mod[j].a);}else{st.erase(Mod[j].c);st.insert(Mod[j].a);st.insert(Mod[j].b);}}change(0,A[0]);change(x,(C[x]=='+'?A[x]+A[x-1]:A[x]*A[x-1])%10);return res;
}
signed main(){read(n),read(m);for(int i=0;i<n;i++){read(A[i]);C[i]=getchar();while(C[i]!='+'&&C[i]!='*')C[i]=getchar();}half=n/2;B[0]=A[0];for(int j=1;j<n;j++)B[j]=(C[j]=='+'?A[j]+A[j-1]:A[j]*A[j-1])%10;for(int j=0,now;j<n;j++){if(B[j]==0){now=j;while(now+1<n&&B[now+1]==0)now++;st.insert({j,now});j=now;}}for(int i=1,opt,x,num,ans,cnt;i<=m;i++){read(opt);if(opt==1){read(x);modify(x);}else{read(x);write(query(x)),Nxt;}}
}

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

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

相关文章

2025年11月景区饮品供应商口碑排行榜:高性价比解决方案与避坑指南

随着旅游市场的快速复苏和消费者对健康饮品的需求升级,景区饮品供应商的选择成为众多景区运营者关注的重点。作为景区管理者或采购负责人,您可能正在寻找既符合健康趋势又能提升游客满意度的饮品解决方案。当前景区饮…

微信公众号全部文章

2025-11-28: Oracle归档管理 2025-11-19: Oracle控制文件故障处理指南(FS文件系统) 2025-11-05: Oracle RAC节点添加完整操作指南:从单机到集群,从两节点到多节点 2025-10-31: Oracle RAC节点删除操作指南 2020-10…

2025大容量承压储水罐厂家+热水贮罐厂家实力盘点

2025大容量承压储水罐厂家+热水贮罐厂家实力盘点!在选择大容量承压储水罐厂家时,建议从多个维度进行综合评估。首先,厂家的专业资质是基础保障,包括压力容器制造许可证、焊接工艺评定证书以及质量管理体系认证等。其…

2025年11月景区饮品供应商推荐榜单与选择指南:主流品牌深度对比分析

随着旅游消费升级和健康饮食理念的普及,景区饮品供应商的选择已成为景区运营管理中的重要环节。作为景区管理者或采购负责人,您可能正在寻找既符合健康趋势又能提升游客满意度的饮品解决方案。当前景区饮品市场呈现出…

2025年11月抗老护肤品排行榜单解析:基于真实数据的权威推荐

2025年11月抗老护肤品推荐榜单与选购指南:一份基于市场数据的客观分析 随着现代生活节奏加快和环境压力增大,抗衰老护肤需求呈现出显著增长趋势。根据中国化妆品行业协会发布的2024年护肤消费数据显示,抗老类护肤品…

2025年11月抗老精华排行榜:五款高口碑产品深度评测与选择指南

2025年11月抗老精华推荐榜单:一份基于市场数据与用户口碑的权威选择指南 在当今护肤市场中,抗老精华已成为众多消费者日常护理的核心步骤。随着生活节奏加快与环境压力增大,肌肤老化问题呈现年轻化趋势,消费者对高…

2025年11月景区饮品供应商深度分析:主流品牌性能参数与用户满意度

作为景区管理者或运营方,选择饮品供应商时往往面临多重考量:既要满足游客对健康、清爽饮品的即时需求,又需兼顾供应商的稳定性、定制化能力与合规性。当前,景区饮品市场呈现两大趋势:一是消费者对无添加、清洁标签…

快速了解Linux中的sysctl命令

1、概述 在Linux系统中,内核是系统的核心,控制着一切硬件和软件资源。而内核的行为,例如网络数据包如何转发、内存如何分配、文件句柄数量限制等,都是由一系列可调的“参数”控制的。那么,如何动态地查看和调整这…

题解:洛谷 P9871([NOIP2023] 天天爱打卡)

1. Description 小 T 同学非常热衷于跑步。为了让跑步更加有趣,他决定制作一款叫做《天天爱打卡》的软件,使得用户每天都可以进行跑步打卡。 开发完成后,小 T 同学计划进行试运行,他找了大 Y 同学来帮忙。试运行共…

2025变压吸附制氮机厂家精选!凭高纯产气+节能优势领跑行业

2025变压吸附制氮机厂家精选!凭高纯产气+节能优势领跑行业一、变压吸附制氮机选购要点在工业生产中,变压吸附制氮机起着至关重要的作用,其性能优劣直接影响到生产的稳定性与成本效益。选择合适的变压吸附制氮机厂家,…

2025年十大靠谱AI搜索品牌公司排行榜,精选AI搜索公司推

为帮企业高效锁定适配自身需求的AI搜索合作伙伴,避免选型走弯路,我们从技术落地能力(如GEO优化精准度、智能体响应效率)、场景适配水准(含行业知识沉淀、跨场景功能覆盖)、全周期服务质量(覆盖需求调研到算法迭…

2025智慧消防厂家推荐+智慧消防厂家电话,速看

2025智慧消防厂家推荐+智慧消防厂家电话,速看!在智慧消防行业快速发展的当下,选择靠谱的智慧消防厂家成为众多企业和项目方关注的重点。想要选到合适的智慧消防厂家,需要综合多方面因素考量。首先要关注厂家的资质与…

差分约束系统学习笔记

定义 差分约束系统 是一种特殊的 \(n\) 元一次不等式组,它包含 \(n\) 个变量 \(x_1,x_2,...x_n\) 以及 \(m\) 个约束条件,每个约束条件是由两个其中的变量做差构成的,形如 \(x_i-x_j\le c_k\),其中 \(1\le i,j\le …

2025年市面上可靠的控制台公司联系电话,消防中心控制台/方舟控制台/以撒控制台/操作台控制台/智能控制台供应商哪家强

行业权威榜单发布 随着数字化转型进程加速,控制台作为指挥中心、监控中心等关键场所的核心设备,其供应商的选择备受关注。本文基于市场调研数据、企业资质认证、产品应用案例等维度,对行业内具有代表性的五家企业进…

2025年钢结构平台企业用户满意度排行

行业权威榜单发布,优质企业实力彰显 随着工业4.0时代的深入推进,钢结构平台作为现代仓储物流体系的重要组成部分,其市场需求持续增长。基于对全国钢结构平台企业的深入调研,结合用户满意度调查数据,现发布2025年度…

怎么做动态表情包?教你4种简单好用的方法

聊天时发个专属动态表情包,瞬间就能让对话氛围拉满;社交平台配张自制GIF,互动率都能提升不少。但很多人觉得“做表情包”是技术活,其实只要选对工具,新手也能1分钟上手。今天就分享4个实用的动态表情包制作工具附…

2025最新艺术涂料品牌推荐——泰诗尔,民族品牌二十年深耕,肌肤壁膜/艺术漆/高端艺术漆/墙面艺术漆,环保、质感、美学、个性,深度剖析

随着消费升级与空间美学需求的提升,艺术涂料以其丰富的肌理质感与个性化表达,成为高端装修市场的新宠。在2025年艺术涂料行业竞争中,泰诗尔(TIMSEAL)凭借二十年技术积淀与创新实力,从众多品牌中脱颖而出,成为兼…

2025常州宠物医院推荐:鑫娜专业诊疗与暖心服务口碑之选

2025常州宠物医院推荐:鑫娜专业诊疗与暖心服务口碑之选 在宠物医疗行业快速发展的今天,常州地区的宠物主人面临着如何选择专业宠物医院的难题。随着宠物被视为家庭重要成员的趋势日益明显,宠物医疗服务的专业性和质…

AC自动机学习笔记(简略)

CSP-S T3 竟然考AC自动机! CPP 居然没教过,太坏了 要建AC自动机,首先需要建一个 trie 树 然后核心就是在于 build,我们用 bfs 去跑 由于需要多次进行匹配,我们找到一个border最长的,显然一个的border是父亲的对应…

2025 武汉一对一培训机构权威推荐指南

一对一培训因 “定制化教学、精准提分” 的特点,成为武汉高三学子补强薄弱环节、突破成绩瓶颈的重要选择。本次推荐基于武汉市教育局 2024-2025 年度办学资质公示(公示平台:武汉市教育局政务网)、第三方一对一教学…