尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

P6000 [CEOI2016] match

P6000 [CEOI2016] match
📅 发布时间:2026/6/19 19:03:36

洛谷

对于暴力写法,我们很容易想到一个 \(O(n^2)\) 的暴力。

我们可以先从左到右枚举需要配对的字符,然后从后往前去找到一个合法且相同的字符配对。

对于怎样才算合法,我们通过此部分内部是否合法,以及前面是否有已选择的括号判断。

在括号本身是合法的情况下,我们处理右边是否合法,对于本身存在解的串,左边也必定合法,可以自己模拟证明。

那么我们还需要找到上一次配对的右端,从这里从后往前开始枚举。可以选择使用搜索,这样可以直接继承上一步的端点位置,直接开始枚举。

由于枚举位置较少,除了最后一个测试点都能过。

代码:

#include<bits/stdc++.h>
using namespace std;
char s[100005],ans[100005],p[100005];
bool f[100005];
int len,cnt;
signed main(){cin>>s+1;len=strlen(s+1);if(len%2==1){cout<<-1;return 0;}f[len+1]=1;for(int i=1;i<=len;i++){if(f[i])continue;bool flag=0;int w;for(int j=i+1;j<=len+1;j++){if(f[j]){w=j;break;}}for(int j=w-1;j>i;j--){if(cnt==0&&s[j]==s[i]){flag=1;ans[j]=')';f[j]=1;break;}if(!cnt||p[cnt]!=s[j])p[++cnt]=s[j];else cnt--;}if(!flag){cout<<-1;return 0;}ans[i]='(';}cout<<ans+1;return 0;
}

时间复杂度的瓶颈明显在于如何找到合适的配对。

第一种做法是哈希,我们使用字符串哈希记录下当前结点未配对的字符,若字符相同且两个点的字符相同,则可以组成合法的括号,直接二分得到配对即可。

代码:

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int base=131;
char s[100005],ans[100005];
int len,p[100005],top;
ull h[100005],b[100005];
vector<pair<ull,int>> e[30];
void init(){for(int i=len;i>=1;i--){if(top&&s[p[top]]==s[i])top--;else{p[++top]=i;h[top]=h[top-1]*base+s[i];}b[i]=h[top];e[s[i]-97].push_back({b[i],i});}if(top){cout<<-1;exit(0);}for(int i=0;i<26;++i)sort(e[i].begin(),e[i].end());
}
int find(int p,ull v,int x){int l=0,r=e[p].size(),ans;while(l<=r){int mid=l+r>>1;if(e[p][mid].first<v)l=mid+1;else if(e[p][mid].first>v)r=mid-1;else{if(e[p][mid].second>x)r=mid-1;else{l=mid+1;ans=e[p][mid].second;}}}return ans;
}
void dfs(int l,int r){if(l>r)return;ans[l]='(',ans[r]=')';if(r-l==1)return;int x=find(s[l]-97,b[l+1],r);ans[x]=')';dfs(l+1,x-1),dfs(x+1,r);
}
signed main(){cin>>s+1;len=strlen(s+1);init();dfs(1,len);cout<<ans+1;return 0;
}

第二种做法,考虑动态规划,设置 \(dp_{i,j}\) 表示以 \(i\) 为最右端,在一个符号为 \(j\) 且在此之后到 \(i\) 可以组成一个合法括号串的最大位置。

我们可以得到方程式:

\[dp_{i,j}=dp_{dp_{i-1,s_i-97}-1,j} \]

看似复杂实际上很简单,相当于连接了两个括号串。

然后怎么处理答案呢?

我们从暴力方法可以通过搜索得到范围,那么我们知道了右端点位置,就可以用右端点找到一个最靠右的点与左端点进行匹配。

代码:

#include<bits/stdc++.h>
using namespace std;
int len,p[100005],cnt,dp[100005][30];
char s[100005],ans[100005];
bool check(){for(int i=1;i<=len;i++){if(cnt&&p[cnt]==s[i]-'a')cnt--;else p[++cnt]=s[i]-'a';}if(cnt)return true;cnt=0;return false;
}
void dfs(int l,int r){if(l>r)return ;int tmp=dp[r][s[l]-97];ans[l]='(',ans[tmp]=')';dfs(l+1,tmp-1),dfs(tmp+1,r);
}
signed main(){cin>>s+1;len=strlen(s+1);if(check()){cout<<-1;return 0;}for(int i=1;i<=len;i++){for(int j=0;j<26;j++)if(dp[i-1][s[i]-97])dp[i][j]=dp[dp[i-1][s[i]-97]-1][j];dp[i][s[i]-97]=i;}dfs(1,len);cout<<ans+1;return 0;
}

相关新闻

  • 汽车智能座舱软件、技术、分类介绍
  • 『NAS』在群晖部署图表绘制工具-Draw.io
  • PowerShell TOTP 身份验证器

最新新闻

  • 2026厦门百达翡丽回收实力排行榜!本地七大正规机构权威排名 - 薛定谔的梨花猫
  • eNSP - BGP 诊断命令实战指南
  • 北京黄金回收避坑攻略:认准“秤不改、火不假、价不虚”这三大准测 - 奢侈品回收测评
  • 联调测试:问题都藏在边界里
  • 覆盖上海近郊全域网点,2026 黄金回收城郊门店综合参考榜单 - 奢侈品回收测评
  • 技术深度解析:Win11Debloat如何实现Windows系统优化与隐私保护架构

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号