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

交互 Codeforces Round 1040 Interactive RBS

题目大意:

交互题。有一个隐藏的括号序列,只由 "(" 和 ")" 组成,保证至少有一个"(" 和一个 ")"。

你需要通过若干次查询猜出这个确定的序列。

Easy Version:最多查询 550 次

Medium Version:最多查询 200 次

Hard Version:最多查询 200 次

Solution:

Easy Version

查询次数限制提示我们一次查询要找到两个元素。

首先我们可以通过二分找到一般情况下第一个 “()” 出现的位置,特例是形如 "))))).....(((((" 的序列。

那么对于一般情况,二分一个mid,查询 [1,mid] 这个连续的子序列,如果查询值不为 0,说明这段序列中存在 “()” 。

于是无论哪种情况,我们都可以找到一个 "(" 和一个 ")" 所在的位置(特例就是 n 和 1 )。

然后我们需要构造一个查询方式,每次查询两个位置,如果这两个位置的不同排列组合情况对应不同的查询值,我们就可以确定地判断这两个位置的元素是什么,官解构造方式如下:

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;#define N 1005int T,n,a[N],pl,pr,ans[N];void solve(int x,int y)
{int num;printf("? 6 %d %d %d %d %d %d\n",x,pr,y,pr,pl,pr);cout.flush();scanf("%d",&num);if(num == 1) ans[x] = ans[y] = 2;if(num == 2) ans[x] = 1,ans[y] = 2;if(num == 3) ans[x] = 2,ans[y] = 1;if(num == 6) ans[x] = ans[y] = 1;return;
}int main()
{scanf("%d",&T);while(T --){memset(ans,0,sizeof ans);scanf("%d",&n);int l,r,mid,x,tmp;l = 2,r = n,tmp = 0;while (l <= r){mid = (l + r) >> 1;printf("? %d ",mid);for (int i = 1;i <= mid;++ i)printf("%d ",i);printf("\n");cout.flush();scanf("%d",&x);if(x) tmp = mid,r = mid - 1;else l = mid + 1;}if(!tmp) pl = n,pr = 1;else pl = tmp - 1,pr = tmp;for (int i = 1;i <= n - 1;i += 2) solve(i,i + 1);if(!ans[n]) solve(n - 1,n);printf("! ");for (int i = 1;i <= n;++ i)if(ans[i] == 1) printf("(");else printf(")");printf("\n");cout.flush();}return 0;
}

Medium Version

官解用的是状压的思想,往二进制方向想,也是十分巧妙。

Hard Version

思考我们一次能否查询更多的位置呢?

先观察到一个小性质:在两个合法括号序列中间随便插一个 ")" 就能把这两个合法序列的贡献分开

例如:

()()()  查询值是 6

()())() 查询值是 3 + 1 = 4

构造这样的查询序列:

"s1))s2)s2))s3)s3)s3))s4)s4)s4)s4)s4))......s12))"

当且仅当si == '(' 的时候,它负责的那一段括号序列才有贡献,并且贡献 = gi * (gi + 1) / 2,其中 gi 是第 i 段的 "si)" pairs 的数目。

那么只需满足:

即可对每一段贡献拆开判断。

这里其实用到的是类似 2^n > 2^(n-1) + ... + 2^1 + 2^0 的思想,这样我们从高位到低位一个个判断,如果 查询值 > gi * (gi + 1) / 2,说明第i段有贡献,si == '(',然后把查询值减掉这段的贡献接着判断下去就可以了。

事实上,根据题目“每次查询的序列长度 k <= 1000” 可以知道,我们一次最多能查询13个位置,但是每次查12个也足够通过 hard version 的限制了,每次13个的原理也是一模一样。

最后要注意的是我们是12个12个的查,最后剩下的未知括号位置少于12的时候,需要特殊处理。(可以直接用easy version的方法把最后几个剩余的位置判断了,简单计算一下这样最多查询次数刚好90多,不到100)

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;#define N 1005int T,n,a[N],pl,pr,res,ans[N],g[20],f[20];void preprocess()
{g[1] = f[1] = res = 1;int now = 1;int sum = 1;for (int i = 2;i <= 12;++ i){while (now * (now + 1) / 2 <= sum) ++ now;g[i] = now;f[i] = now * (now + 1) / 2;sum += f[i];res += g[i];}res = res * 2 + 12;return;
}void print(int tot,int pos)
{for (int i = 1;i <= tot;++ i)printf("%d %d ",pos,pr);printf("%d ",pr);return;
}void solve(int x,int y)
{printf("? %d ",res);for (int i = x;i <= y;++ i){int id = i - x + 1;print(g[id],i);}printf("\n");cout.flush();int num;scanf("%d",&num);for (int i = y;i >= x;-- i){int id = i - x + 1;if(num >= f[id]) num -= f[id],ans[i] = 1;else ans[i] = 2;}return;
}void sol(int x,int y)
{int num;printf("? 6 %d %d %d %d %d %d\n",x,pr,y,pr,pl,pr);cout.flush();scanf("%d",&num);if(num == 1) ans[x] = ans[y] = 2;if(num == 2) ans[x] = 1,ans[y] = 2;if(num == 3) ans[x] = 2,ans[y] = 1;if(num == 6) ans[x] = ans[y] = 1;return;
}int main()
{preprocess();scanf("%d",&T);while (T --){memset(ans,0,sizeof ans);scanf("%d",&n);int l,r,mid,x,tmp;l = 2,r = n,tmp = 0;while (l <= r){mid = (l + r) >> 1;printf("? %d ",mid);for (int i = 1;i <= mid;++ i)printf("%d ",i);printf("\n");cout.flush();scanf("%d",&x);if(x) tmp = mid,r = mid - 1;else l = mid + 1;}if(!tmp) pl = n,pr = 1;else pl = tmp - 1,pr = tmp;int now = 0;for (int i = 1;i + 11 <= n;i += 12)solve(i,i + 11),now = i + 11;if(now < n){for (int i = now + 1;i <= n - 1;i += 2) sol(i,i + 1);if(!ans[n]) sol(n - 1,n);}printf("! ");for (int i = 1;i <= n;++ i)if(ans[i] == 1) printf("(");else printf(")");printf("\n");cout.flush();}return 0;
}

一道非常巧妙的构造序列交互题^^

http://www.lryc.cn/news/608473.html

相关文章:

  • 深入 Go 底层原理(十一):Go 的反射(Reflection)机制
  • 基于深度学习的医学图像分析:使用GAN实现医学图像增强
  • SpringBoot 启动富文本文字更改
  • 基于 LightGBM 的二手车价格预测
  • 一种基于入侵杂草优化算法(IWO)的聚类算法,并与K-Means、高斯混合模型(GMM)进行对比,Matlab
  • 用键盘快速移动Word和WPS文字中的选中段落
  • 【笔试真题】2024秋招京东后端开发岗位-第一批笔试
  • 数据链路层、NAT、代理服务、内网穿透
  • 使用 MySQL Shell 进行 MySQL 单机到 InnoDB Cluster 的数据迁移实践
  • 数字化生产管理系统设计
  • 从零开始构建AI Agent评估体系:12种LangSmith评估方法详解
  • cuda编程笔记(12)--学习cuFFT的简单使用
  • Java单元测试和设计模式
  • 【LeetCode 热题 100】739. 每日温度——(解法一)单调栈+从右到左
  • 【语音技术】什么是动态实体
  • 【Django】-6- 登录用户身份鉴权
  • Mybatis学习之获取参数值(四)
  • 第14届蓝桥杯Python青少组中/高级组选拔赛(STEMA)2023年1月15日真题
  • STM32学习记录--Day6
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘seaborn’问题
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现道路车辆事故的检测识别(C#代码UI界面版)
  • SpringBoot 服务器配置
  • 面经——电子电路技术知识详解
  • 【Python3教程】Python3高级篇之网络编程
  • 文心4.5开源测评:国产大模型的轻量化革命与全栈突破
  • GaussDB 约束的使用举例
  • 高效轻量的C++ HTTP服务:cpp-httplib使用指南
  • Redis核心机制与实践深度解析:从持久化到分布式锁
  • 路面障碍物识别漏检率↓76%:陌讯多模态融合算法实战解析
  • 基于 LFU 策略的存储缓存系统设计与实现