Replace
Replace
题意
给你一个长度为 的序列 ,有 次询问,每次询问对于一个区间 需要操作多少次才能变成区间 ,无解输出 。其中一次操作指原区间变成 。
solution
看了feecle大佬的题解后对其中的结论有也许是另一种理解方式。
首先题目的操作与取 有关,因此通过丰富的经验和敏锐的观察力显然我没有可以发现:
证明(或者应该叫理解方式):对于每个 ,设 , 对应区间 ,其中相邻的 对应区间至少有一个端点重合。因此所有的 并成连续的一段区间,其中最左的一个端点和最右的一个端点就是 的两端。可见等式是成立的。
蒟蒻的我不能直接观察出推论,但是也许可以这么想:我们考虑对所有 再进行一次操作,看看会发生什么。 是若干段首尾相接的区间。每个区间会变成区间最小值和最大值为端点的新区间。由于区间是首尾相接的,因此新区间要么首尾相接要么相交得更多,而所有新区间的最左端点和最右端点一定等于所有区间的最小值和最大值,因此对这些 再进行一次操作,得到的区间 。
以此类推,可以得到 。
所以我们不需要求所有的 ,只需要求所有的 。然后是 RMQ 问题求区间最小值和最大值,ST 表即可。
因为 ,所以显然操作 次能否得到区间 的 满足单调性, 越大越容易得到指定区间。
因此考虑倍增。先求所有 ,然后求所有 ,以此类推,每一层都要做一次 RMQ。时间和空间都是 。
对每个询问,倍增,每次计算 RMQ 判断是否可以得到区间 即可。时间复杂度 。
总时间复杂度是 。
据说猫树可以单 ?感觉不会啊,会的大佬欢迎分享。
code
如果你对 ST 表比较熟练,代码不算难写。
#include<bits/stdc++.h> // #define LOCAL #define sf scanf #define pf printf #define rep(x,y,z) for(int x=y;x<=z;x++) #define per(x,y,z) for(int x=y;x>=z;x--) using namespace std; typedef long long ll; constexpr int N=1e5+7; #define isdigit(x) (x>='0'&&x<='9') template <typename T> void read(T &x) { x=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) ; for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0'; } template <typename T> void write(T x,char ch) { static int st[20]; int top=0; do { st[top++]=x%10; x/=10; }while(x); while(top) putchar(st[--top]+'0'); putchar(ch); } int n,q; int a[N]; int l,r; typedef pair<int,int> pii; #define fi first #define se second pii st[50][25][N]; pii cal(pii a,pii b) { return {min(a.fi,b.fi),max(a.se,b.se)}; } pii _cal(int p,pii x) { if(x.fi==x.se) return x; int lg=__lg(x.se-x.fi); return cal(st[p][lg][x.fi],st[p][lg][x.se-(1<<lg)]); } #define mp make_pair int main() { read(n),read(q); rep(i,1,n) read(a[i]); rep(i,1,n-1) st[0][0][i]={min(a[i],a[i+1]),max(a[i],a[i+1])}; int lg=__lg(n); rep(k,1,lg) for(int i=1;i+(1<<k)-1<=n-1;i++) st[0][k][i]=cal(st[0][k-1][i],st[0][k-1][i+(1<<(k-1))]); rep(p,1,lg<<1) { rep(i,1,n-1) st[p][0][i]=_cal(p-1,st[p-1][0][i]); rep(k,1,lg) for(int i=1;i+(1<<k)-1<=n-1;i++) st[p][k][i]=cal(st[p][k-1][i],st[p][k-1][i+(1<<(k-1))]); } rep(i,1,q) { read(l),read(r); if(l==1&&r==n) { puts("0"); continue; } if(l==r) { puts("-1"); continue; } pii y={l,r}; int cnt=0; per(p,lg<<1,0) { pii x=_cal(p,y); if(x!=mp(1,n)) y=x,cnt+=(1<<p); } if(y!=mp(1,n)) y=_cal(0,y),cnt++; if(y==mp(1,n)) write(cnt,'\n'); else puts("-1"); } }
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/18470792
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现