当前位置: 首页 > news >正文

sm2025 模拟赛23 (2025.10.18)

文章目录

  • T1 前后缀排序
  • T2 回家的路
  • T3 栈模拟
  • T4 括号游戏3

T1 前后缀排序

link
思路
考虑删掉第 iii 位会有什么影响。分以下三种:
{ai=ai−1→i−1,iai>ai−1→i,i−1ai<ai−1→i−1,i\begin{cases} a_i=a_{i-1} & \rightarrow i-1, i \\ a_i \gt a_{i-1} & \rightarrow i,i-1 \\ a_i \lt a_{i-1} & \rightarrow i-1,i \end{cases}ai=ai1ai>ai1ai<ai1i1,ii,i1i1,i
于是我们可以确定 si−1s_{i-1}si1sis_isi 的大小关系。手动模拟样例,将连续一段字符缩成一个点,后面的一个点的排名最多会在前一个点之前,不会在前面多个点之前,于是可以用类似单调栈维护,复杂度 O(n)O(n)O(n)

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int stk[maxn],b[maxn];
struct NODE{ int x,cnt; }a[maxn];
string st;
int main(){freopen("sort.in","r",stdin);freopen("sort.out","w",stdout);int id,t; scanf("%d%d",&id,&t);while(t--){int n; scanf("%d",&n); cin>>st; int m=0,top=0,tot=0; st=" "+st;a[++m]={1,1},stk[++top]=1;for(int i=2;i<=n;i++){if(st[i]==st[i-1]) a[m].cnt++;else if(st[i]<st[i-1]){a[++m]={i,1};stk[++top]=m;}else{b[++tot]=stk[top--];a[++m]={i,1};stk[++top]=m;}}for(int i=1;i<=top;i++)for(int j=1;j<=a[stk[i]].cnt;j++)printf("%d ",a[stk[i]].x+j-1);for(int i=tot;i>=1;i--)for(int j=1;j<=a[b[i]].cnt;j++)printf("%d ",a[b[i]].x+j-1);printf("\n");}return 0;
}

T2 回家的路

link
思路
首先求出每个点的起始位置和终点位置,它只会在这个区间中移动,且它到达家后就不会再移动,此时若另外一个点经过它,那么这个点是直接跳过它的。于是一个点需走的步数相当于圆上对应的那段弧长减去这条弧所包含的弧的数量。具体直接破环为链,然后二维数点即可。

反思
没有跳出原始题目,局限于考虑每一轮的限制和变化,没有解决某个点回家路上经过的一些新到达家的点怎么做这一问题。所以要根据题目化简模型,适当跳出原始思路重新思考。

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;int tree[maxn];
void Add(int x){while(x) tree[x]++,x-=x&(-x);
}int n;
int Ask(int x){int s=0;while(x<=n*2) s+=tree[x],x+=x&(-x);return s;
}int ans[maxn];
struct NODE{ int x,id; }b[maxn];
int main(){freopen("home.in","r",stdin);freopen("home.out","w",stdout);int id,t; scanf("%d%d",&id,&t);while(t--){scanf("%d",&n);for(int i=1,x;i<=n;i++){scanf("%d",&x);if(x>=i) b[x]={i,x},b[x+n]={i+n,x};else b[x+n]={i,x};}for(int i=1;i<=n+n;i++)if(b[i].id){ans[b[i].id]=i-b[i].x-Ask(b[i].x);Add(b[i].x);}for(int i=1;i<=n;i++)printf("%d ",ans[i]);printf("\n");for(int i=1;i<=n+n;i++)tree[i]=0,b[i]={0,0};}return 0;
}

T3 栈模拟

link
思路
对于每个询问重复模拟显然爆炸,我们希望每个数最多被遍历一次。
考虑图论。让 i→ai,topi \rightarrow a_{i,top}iai,top 。如果只连一层的话会形如基环树森林,观察到如果走到一个环那么走一圈之后又会回到起点,于是考虑消环,将环上所有点的栈顶 pop 掉,于是又进入下一层继续连边直到碰到第一个为栈为空的点就是答案。注意求答案的细节避免复杂度变劣。

反思
要转到图上考虑。

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;int top,stk[maxn],ans[maxn];
bool vis[maxn];
stack<int>a[maxn];
int Dfs(int x){if(ans[x]) return ans[x];if(!a[x].size()) return ans[x]=x;if(vis[x]){while(x!=stk[top]){int u=stk[top--];a[u].pop();vis[u]=0;}vis[x]=0; a[x].pop(); top--;return Dfs(x);}vis[x]=1,stk[++top]=x;return Dfs(a[x].top());
}int main(){freopen("stack.in","r",stdin);freopen("stack.out","w",stdout);int id,n; scanf("%d%d",&id,&n);for(int i=1,k;i<=n;i++){scanf("%d",&k);for(int j=1,x;j<=k;j++){scanf("%d",&x); a[i].push(x);}}top=0;for(int i=1;i<=n;i++){int tmp=Dfs(i);while(top) ans[stk[top--]]=tmp;}for(int i=1;i<=n;i++)printf("%d ",ans[i]);return 0;
}

T4 括号游戏3

link
思路
通过模拟样例和贪心猜想可以得到每次删除相邻的括号对一定是最优的。于是可以发现删除的一段是一个合法的括号序列。
出现了子问题形式,考虑 dp 。记 fif_ifi 表示 Si,i+1,…,nS_{i,i+1,\dots,n}Si,i+1,,n 这个后缀子串中经过一些删除操作使得字典序最小的串。若保留 sis_isifi←si+fi+1f_i \leftarrow s_i+f_{i+1}fisi+fi+1 ;若删除 sis_isi ,要保证 sis_isi(sis_isi 的后面存在与之匹配的 ) ,记其位置为 jjj ,有 fi←fj+1f_i \leftarrow f_{j+1}fifj+1 。这样直接转移是 O(n2)O(n^2)O(n2) 的。
考虑优化记录转移的串和计较两个串的大小。前者可以维护此时串中第一个和下一个字符的原位置,这样可以倍增跳出整个串;后者可以先倍增跳出两个串的 LCP 然后比较其下一个字符就好。这样复杂度为 O(nlogn)O(nlogn)O(nlogn) 。求 LCP 可以用哈希帮助,注意要双哈希不然单哈希对于括号序列容易发生冲突。感觉这个优化很牛啊。

反思
得到了贪心小结论然后从前往后贪心地判断每一组相邻的 () 删不删,但是发现不一定需要前缀最优,然后掉线。其实从后往前 dp 就可以了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=3e5+5;
const ll BS=47,BS2=71,mod=998244353,mod2=1e9+7;int n,fa[maxn][23],nxt[maxn];
ll hs[maxn][23],hs2[maxn][23];
string st;
bool Cmp_(int x,int y){int x2=x;while(nxt[x2]!=x2) x2=nxt[x2];if(x2==n+1) return true;// 判断从 [x,n] 是否直接为一个合法括号序列 for(int i=20;i>=0;i--)if(fa[x][i]&&fa[y][i]&&hs[x][i]==hs[y][i]&&hs2[x][i]==hs2[y][i]) x=fa[x][i],y=fa[y][i];return st[x]<st[y];
}int stk[maxn],pos[maxn];
ll pw[maxn],pw2[maxn];
int main(){cin>>st; n=st.size(); st=" "+st; int top=0;for(int i=1;i<=n;i++){if(st[i]=='(') stk[++top]=i;else if(top) nxt[stk[top--]]=i+1;}nxt[n+1]=n+1;pw[0]=pw2[0]=1;for(int i=1;i<=n;i++){pw[i]=pw[i-1]*BS%mod;pw2[i]=pw2[i-1]*BS2%mod2;}pos[n+1]=n+1;for(int i=n;i>=1;i--){pos[i]=i;fa[i][0]=pos[i+1],hs[i][0]=hs2[i][0]=(st[i]=='('?1:0);for(int j=0;j<20;j++){fa[i][j+1]=fa[fa[i][j]][j];hs[i][j+1]=(hs[fa[i][j]][j]*pw[1<<j]%mod+hs[i][j])%mod;hs2[i][j+1]=(hs2[fa[i][j]][j]*pw2[1<<j]%mod2+hs2[i][j])%mod2;}if(nxt[i]&&Cmp_(nxt[i],i)){pos[i]=pos[nxt[i]];for(int j=0;j<=20;j++){fa[i][j]=fa[nxt[i]][j];hs[i][j]=hs[nxt[i]][j];hs2[i][j]=hs2[nxt[i]][j];}}}for(int i=pos[1];i<=n;i=fa[i][0])cout<<st[i];return 0;
}
http://www.dtcms.com/a/500324.html

相关文章:

  • 永泰城乡建设网站有哪些网站使用ftp
  • 力扣 547. 省份数量
  • 网站设计用于制作网页的工具软件
  • 长沙官网网站制作公司梅江区建设局网站
  • 国外的电商网站有哪些方面雪军miui一键优化
  • DAY40训练和测试的规范写法
  • 大麦抢票脚本技术解析
  • python:requests+beautifulSoup
  • 网站广东省备案系统设计之家官网首页
  • 建设银行悦生活网站小程序api接口怎么对接
  • Win11安装 Ubuntu 22.04 子系统 - WSL2 - 安装完迁移到其它盘
  • 锂电池保护芯片的船运模式
  • Foundation 折叠列表
  • 卫浴建材网站建设建站seo推广
  • 青岛网站建设兼职做企业网站有什么工作内容
  • 连云港网站建设优化百度站长平台清退
  • Orleans 流系统握手机制详解
  • 视觉网络网站辽宁鞍山网站建设
  • 最新项目贺州seo
  • 飞手通航内蒙古基地落子锡林郭勒 携手疆空科技激活北疆低空经济
  • 品牌宝免费网站手机网站策划
  • 宣传网站制作泰安哪里可以做网站
  • 简述网站建设的一般流程源码网站违法吗
  • 厦门唯一官方网站vps网站能打开
  • 怎么投诉没有备案就已经运营网站wordpress 企业 自适应
  • 网站设计与管理开发电商网站多少钱
  • 网站域名后缀有哪些个人小公司怎么注册
  • 第三章 常用协议
  • 网站备案管谁要幕布新乡新手学做网站
  • ‌《项目整体管理与范围管理核心知识点总结》