Codeforces Round 930 (Div. 2)(A,B,C,D)

news2024/11/19 18:18:34

比赛链接

C是个交互,D是个前缀和加二分。D还是很难写的。


A. Shuffle Party

题意:

您将得到一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 。最初,每个 1 ≤ i ≤ n 1 \le i \le n 1in 对应 a i = i a_i=i ai=i 。整数 k ≥ 2 k \ge 2 k2 的运算 swap ( k ) \texttt{swap}(k) swap(k) 定义如下:

  • d d d 是不等于 k k k 本身的 k k k 的最大除数 † ^\dagger

然后交换元素 a d a_d ad a k a_k ak

假设您按此顺序对每个 i = 2 , 3 , … , n i=2,3,\ldots, n i=2,3,,n 执行 swap ( i ) \texttt{swap}(i) swap(i) 。在结果数组中查找 1 1 1 的位置。

换句话说,在执行这些操作之后,找到这样的 j j j,满足 a j = 1 a_j = 1 aj=1 † ^\dagger 如果存在整数 z z z 使得 y = x ⋅ z y = x \cdot z y=xz ,则整数 x x x y y y 的除数。

思路:

手玩一下其实比较容易看出来性质。我们只关注 1 1 1 的移动情况,一开始第 1 1 1 个位置和第 2 2 2 个位置交换位置,然后是第 2 2 2 个位置和第 4 4 4 个位置交换位置,移动路径是 1 → 2 → 4 → 8 → … 1\rightarrow2\rightarrow4\rightarrow8\rightarrow\dots 1248

思考一下为什么。因为 2 2 2 是最小的质因数,所以 x x x 第一个被后面交换的数就是 2 ∗ x 2*x 2x。换句话说就是对一个位置,我们交换的是这个位置的最大约数,反过来就是某个数最先会被它的最小倍数交换一次。

因此答案就是 ≤ n \le n n 的最大的 2 2 2 的幂。

code:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int T,n;

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		cout<<(1<<(int)(log2(n)))<<endl;
	}
	return 0;
} 

B. Binary Path

题意:

您将得到一个由0和1填充的 2 × n 2 \times n 2×n 网格。设第 i i i 行与第 j j j 列的交点处的数字为 a i j a_{ij} aij 。在左上角的单元格 ( 1 , 1 ) (1, 1) (1,1) 中有一只蚱蜢,它只能向右或向下跳一个单元格。它希望到达右下角的单元格 ( 2 , n ) (2, n) (2,n)

考虑长度为 n + 1 n+1 n+1 的二进制串,它由写在路径的单元格中的数字组成,而不改变它们的顺序。

您的目标是:

  1. 通过选择任何可用的路径,查找您可以获得的字典序最小的 † ^\dagger 字符串

  2. 找出产生这个字典序最小字符串的路径数。

† ^\dagger 如果两个字符串 s s s t t t 的长度相同,则 s s s 在字典序上小于 t t t 当且仅当在 s s s t t t 不同的第一个位置,字符串 s s s 的元素比 t t t 中的对应元素小。

思路:

考虑怎样才能得到字典序最小的字符串路径。因为我们只能向下走一步,不能向上走,其他时候都是向右走,所以我们只要找到这个拐点就可以了。

考虑在第一行走的时候什么时候要拐弯。如果我们现在在 ( 1 , i ) (1,i) (1,i),那么右边和下边有三种情况。

  1. 右边是 1 1 1,下边是 0 0 0。这时必须走下边。
  2. 右边是 0 0 0,下边是 1 1 1。这时必须走右边。
  3. 右边和下边一样。这时走哪里都可以。

发现我们最保险的行走策略就是贪心地向右走,直到不得不向下走才拐弯。但是这样只能找到一种可行的行走方案。

发现我们在不得不拐弯之前可能有一段是走哪里都可以的点,有一个点就会产生一种可行的行走方案,所以我们统计一下在最保险的行走方案的拐点前面有多少走哪里都可以的拐点个数即可。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn=2e5+5;

int T,n;
string mp[3];

int main(){
	cin>>T;
	while(T--){
		cin>>n>>mp[1]>>mp[2];
		mp[1]=" "+mp[1];
		mp[2]=" "+mp[2];
		
		int cnt=0;
		string str;
		for(int i=1;i<=n;i++){
			if(i==n){
				str=mp[1].substr(1,i)+mp[2].substr(i,n);
				cnt++;
				break;
			}
			
			if(mp[1][i+1]=='0'){
				if(mp[2][i]=='1')cnt=0;
				else cnt++;
			}
			else {
				if(mp[2][i]=='0'){
					str=mp[1].substr(1,i)+mp[2].substr(i,n);
					cnt++;
					break;
				}
				else cnt++;
			}
		}
		cout<<str<<endl<<cnt<<endl;
	}
	return 0;
}

C. Bitwise Operation Wizard

题意:

这是一个交互问题。

有一个秘密序列 p 0 , p 1 , … , p n − 1 p_0, p_1, \ldots, p_{n-1} p0,p1,,pn1 ,它是 { 0 , 1 , … , n − 1 } \{0,1,\ldots,n-1\} {0,1,,n1} 的一个排列。

您需要找到任意两个索引 i i i j j j ,使得 p i ⊕ p j p_i \oplus p_j pipj 最大,其中 ⊕ \oplus 表示 按位异或。

为此,您可以询问查询。

每个查询都具有以下形式:选择任意索引 a a a b b b c c c d d d 0 ≤ a , b , c , d < n 0 \le a,b,c,d \lt n 0a,b,c,d<n )。接下来,检验程序将计算 x = ( p a ∣ p b ) x = (p_a \mid p_b) x=(papb) y = ( p c ∣ p d ) y = (p_c \mid p_d) y=(pcpd) ,其中 ∣ | 表示 按位或。最后,您将收到 x x x y y y 之间的比较结果。换句话说,您被告知是否 x < y x \lt y x<y x > y x \gt y x>y x = y x = y x=y 。请查找任意两个索引 i i i j j j 0 ≤ i , j < n 0 \le i,j \lt n 0i,j<n ),使得 p i ⊕ p j p_i \oplus p_j pipj 在所有此类对中最大,最多使用 3 n 3n 3n 个查询。

如果有多对索引满足条件,则可以输出其中的任何一对。

思路:

先想一想 p i ⊕ p j p_i \oplus p_j pipj 的最大值是什么,不难想到应该是 n − 1 n-1 n1 的最高位二进制位和它所有低位的二进制位全部置为 1 1 1 时的数,形式化地讲,假设 n − 1 n-1 n1 的最高位二进制位是第 x x x 位,那么异或的最大值就是 2 x + 1 − 1 2^{x+1}-1 2x+11

那么我们应该怎么得到这个最大值,也不难想,首先找到一个至少最高位二进制位为 1 1 1 的数,再找到一个正好和它互补的另一个数,这样异或出来就是最大值了。因为第二个数的最高位为 0 0 0,所以这个数一定小于第一个数,再加上第一个数我们可以选择不超过 n − 1 n-1 n1 的数,因此两个数我们一定是可以找得到的。

咋找呢,发现两个相同的数 或的结果 是这个数本身,所以我们令 a = b = p i , c = d = p j a=b=p_i,c=d=p_j a=b=pi,c=d=pj,这就相当于比较 p i , p j p_i,p_j pi,pj 的大小了。因此用这种方法可以用 n − 1 n-1 n1 次比较找到最大或者最小值。我们找到 p p p 中的最大值,这个最大值至少最高位二进制位为 1 1 1,这样我们就找到了其中一个数。

然后问题来了,询问的结果返回的是或的结果,而我们需要的是异或的结果,拿我们怎么找到另一个正好互补的数呢。发现 我们找到的数和另一个数或出来的结果是 2 x + 1 − 1 2^{x+1}-1 2x+11 的所有满足条件的另一个数中,正好互补的那个数是最小的

所以我们可以先把所有满足 或的结果是最大值 的另一个数找出来,然后再在这些数里找最小值即可。

code:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

int T,n;
char st;

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		int idx=0;//找到n-1的位置 
		for(int i=1;i<n;i++){
			cout<<"? "<<idx<<" "<<idx<<" "<<i<<" "<<i<<endl;
			cin>>st;
			if(st=='<')idx=i;
		}
		
		vector<int> a;
		a.push_back(0);
		for(int i=0;i<n;i++){
			if(i==idx)continue;
			cout<<"? "<<idx<<" "<<a[0]<<" "<<idx<<" "<<i<<endl;
			cin>>st;
			if(st=='<'){
				a.clear();
				a.push_back(i);
			}
			else if(st=='=')a.push_back(i);
		}
		
		int idx2=a[0];
		for(auto x:a){
			cout<<"? "<<idx2<<" "<<idx2<<" "<<x<<" "<<x<<endl;
			cin>>st;
			if(st=='>')idx2=x;
		}
		
		cout<<"! "<<idx<<" "<<idx2<<endl;
	}
	return 0;
}

D. Pinball

题意:

有一个长度为 n n n 的一维网格。网格的第 i i i 个单元格包含字符 s i s_i si ,该字符为“<”或“>”。当弹球被放置在其中一个单元上时,它根据以下规则移动:

  • 如果弹球在第 i i i 个单元格上且 s i s_i si 是’<‘,那么弹球在下一秒钟向左移动一个单元格。如果 s i s_i si 是’>',它将向右移动一个单元格。

  • 在弹球移动后,字符 s i s_i si 被反转(比如如果 s i s_i si 曾经是’<‘,它就会变成’>',反之亦然)。

  • 弹球从左边界或从右边界离开网格时停止移动。

您需要回答 n n n独立查询。在第 i i i 个查询中,将在第 i i i 个单元格上放置一个弹球。请注意,我们总是在初始网格上放置一个弹球。

对于每个查询,计算弹球离开网格所需的秒数。可以证明,弹球总是在有限的步数内离开网格。

思路:

看视频可能会比较好理解

对傻逼二分一点好感都没有。之前调一道二分题调到凌晨三四点调不出来,中间父母一直在吵架,完全没心情想题,结果觉也没睡好,白天还要赶火车,还晕车。

先手玩一下,发现弹球向一个方向走的时候,如果箭头都是顺着它行走的方向,那么弹球就可以一直走下去,直到遇到第一个反方向的箭头(左边的小于号,右边的大于号),它就会被打回来,这时,小球之前走过的路线因为刚刚方向翻转了,小球就可以畅通无阻地走回起点,然后再向起点另一边走。而且第一个反方向的箭头也被消除了,加入到了前面那段畅通无阻的路线,等到下次再走这一边的时候就可以向右边更远的地方行走。

小球就这样来来回回地走,左边每有一个大于号,小球就会在左边被弹回来一次,同理,右边每有一个小于号,小球就会在右边被弹回来一次,弹来弹去,肯定有一边的反方向箭头不够用,然后小球就会在这边走出边界。那么在哪边走出去呢?两边各消耗了几个反方向箭头?

不妨设左边的大于号的个数为 gn \texttt{gn} gn,右边小于号的个数为 ln \texttt{ln} ln。若弹球最后从左边界弹出,说明右边的小于号很多。若:

  1. 初始方向向右,那么需要满足 l n > g n ln>gn ln>gn,这时实际会使用 g n + 1 gn+1 gn+1 个右边小于号。
  2. 初始方向向左,那么需要满足 l n > = g n ln>=gn ln>=gn,这时实际会使用 g n gn gn 个右边小于号。

其他情况就是从右边界弹出的情况,若:

  1. 初始方向向左,那么需要满足 g n > l n gn>ln gn>ln,这时实际会使用 l n + 1 ln+1 ln+1 个右边小于号。
  2. 初始方向向右,那么需要满足 g n > = l n gn>=ln gn>=ln,这时实际会使用 l n ln ln 个右边小于号。

知道了来回弹了几次,从哪个边界出去了,那么怎么计算步数呢?

我们看一下小球移动的路径,发现路径可以看成:若干个 小球从起点走到一边的反方向箭头再回到起点 的段相接,最后再加上一个从起点走出边界的段即可。而小球从起点走到某个方向的反方向箭头,然后再回到起点的长度,其实就相当于两倍的起点到这个箭头的距离。请添加图片描述

假设我们向右走,起点在 i i i,右边的第 j j j 个反方向箭头位置为 i d x j idx_j idxj,实际使用了 l n ln ln 个箭头。单个的箭头我们可以直接算,就是 i d x j − i idx_j-i idxji。如果多个箭头同时计算,相当于 ∑ k i d x k − i ∗ l n \sum_kidx_k-i*ln kidxkiln。我们可以使用前缀和维护前面的东西,这样就可以 O ( 1 ) O(1) O(1) 查询一边的多个箭头的路径。起点右边也可以这样处理(可以正着算前缀和,也可以反着算也就是后缀和 ,我是反着来算的,这样写法上比较对称),这样两边各查询一遍,再加上从起点走出边界的那段就是答案了。

不过处理出了前缀和,我们知道有一边可能用不掉所有箭头,我们需要找到实际用到的箭头的位置,查询它的前缀和才对,这就需要二分查找了。

code:

这里第47行重载了二分查找的比较函数,从而实现了自定义规则的二分查找。具体用法可以参考:讲解

这里的 [](ll val,ll ele)->bool{return ele<val;} 实现的功能 是二分查找第一个小于 v a l u e value value 的位置,然后后面 -sg-1 得到的就是最后一个大于等于 v a l u e value value 的位置。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=5e5+5;
typedef long long ll;

int T,n;
char str[maxn];

ll sl[maxn],sg[maxn],s1[maxn],s2[maxn];

int main(){
	cin>>T;
	while(T--){
		cin>>n>>str+1;
		sl[0]=s1[0]=sg[n+1]=s2[n+1]=0;
		for(int i=1;i<=n;i++){
			sl[i]=sl[i-1]+(str[i]=='<');
			s1[i]=s1[i-1]+(str[i]=='<')*i;
		}
		for(int i=n;i>=1;i--){
			sg[i]=sg[i+1]+(str[i]=='>');
			s2[i]=s2[i+1]+(str[i]=='>')*(n-i+1);
		}
		
//		for(int i=1;i<=n;i++)cout<<sl[i]<<" \n"[i==n];
//		for(int i=1;i<=n;i++)cout<<sg[i]<<" \n"[i==n];
//		for(int i=1;i<=n;i++)cout<<s1[i]<<" \n"[i==n];
//		for(int i=1;i<=n;i++)cout<<s2[i]<<" \n"[i==n];
//		cout<<endl;

		for(ll i=1,ln,gn,idx;i<=n;i++){
			ln=sl[n]-sl[i];//右边小于号数量 
			gn=sg[1]-sg[i];//左边大于号数量 
			if((str[i]=='>' && ln>gn) || (str[i]=='<' && ln>=gn)){//右边小于号太多了,从左边界弹出 
				if(str[i]=='>')ln=gn+1;//实际用到的小于号数量 
				else ln=gn;
				
				idx=lower_bound(sl+i,sl+n+1,ln+sl[i])-sl;
				cout<<(s1[idx]-s1[i]-1ll*i*ln+s2[1]-s2[i]-1ll*(n-i+1)*gn)*2+i<<" ";
			}
			else {
				if(str[i]=='<')gn=ln+1;//实际用到的大于号数量 
				else gn=ln;
				
				idx=upper_bound(sg+1,sg+i+1,gn+sg[i],[](ll val,ll ele)->bool{return ele<val;})-sg-1;
				cout<<(s1[n]-s1[i]-1ll*i*ln+s2[idx]-s2[i]-1ll*(n-i+1)*gn)*2+(n-i+1)<<" ";
			}
		}
		cout<<endl;
	}
	return 0;
}

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

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

相关文章

STM32 使用gcc编译介绍

文章目录 前言1. keil5下的默认编译工具链用的是哪个2. Arm编译工具链和GCC编译工具链有什么区别吗&#xff1f;3. Gcc交叉编译工具链的命名规范4. 怎么下载gcc-arm编译工具链参考资料 前言 我们在STM32上进行开发时&#xff0c;一般都是基于Keil5进行编译下载&#xff0c;Kei…

QT文件读写操作和内容提取

访问IO设备&#xff0c;需要先调用open()来设置正确的OpenMode(例如ReadOnly或ReadWrite) 打开设备后后&#xff0c;使用write() 或putChar() 写入数据到文件和设备&#xff0c;并通过调用read()&#xff0c;readLine() 或readAll() 进行读取&#xff1b;使用完设备后&#xf…

深度学习十大算法之长短时记忆网络(LSTM)

一、长短时记忆网络&#xff08;LSTM&#xff09;的基本概念 长短时记忆网络&#xff08;LSTM&#xff09;是一种特殊类型的循环神经网络&#xff08;RNN&#xff09;&#xff0c;主要用于处理和预测序列数据的任务。LSTM由Hochreiter和Schmidhuber于1997年提出&#xff0c;其…

腾讯云GPU云服务器_并行计算_弹性计算_AI_深度学习

腾讯云GPU服务器是提供GPU算力的弹性计算服务&#xff0c;腾讯云GPU服务器具有超强的并行计算能力&#xff0c;可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景&#xff0c;腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

【Word自动化办公】使用python-docx对Word进行操作

目录 一、环境安装 二、文档各组成结构获取 2.1 组成结构讲解 2.2 段落run对象的切分标准 三、获取整篇文档内容 四、写入指定样式的数据 4.1 通过add_paragraph与add_run参数添加样式 4.2 单独设置文本样式 五、添加标题 六、换行符&换页符 七、添加图片数据 …

pytest之yaml格式测试用例读写封装

pytest之yaml格式测试用例读写封装 pytest之parametrize&#xff08;&#xff09;实现数据驱动YAML格式测试用例读/写/清除/封装结构类型Maps类型数组类型 pytestparametrizeyamltest_api.pyget_token.yaml pytest之parametrize&#xff08;&#xff09;实现数据驱动 pytest.ma…

文件上传二—WEB攻防-PHP应用文件上传中间件CVE解析第三方编辑器已知CMS漏洞

演示案例&#xff1a; PHP-中间件-上传相关-Apache&NginxPHP-编辑器-上传相关-第三方处理引用PHP-CMS源码-上传相关-已知识别到利用 #PHP-中间件-上传相关-Apache&Nginx 复现漏洞环境&#xff1a;vulhub &#xff08;部署搭建看打包视频&#xff09; 由于PHP搭建常用中…

【机器学习300问】46、什么是ROC曲线?

一、二分类器的常用评估指标有哪些&#xff1f; 二分类器是机器学习领域中最常见的也是应用最广泛的分类器。评价二分类器的指标也很多&#xff0c;下面列出几个我之前重点写文章介绍过的指标。 &#xff08;1&#xff09;准确率&#xff08;Accuracy&#xff09; 定义为分类正…

Centos上安装Harbor并使用

harbor的安装与使用 Harbor介绍安装前的准备工作为Harbor自签发证书安装Harbor安装docker开启包转发功能和修改内核参数安装harbor扩展 Harbor 图像化界面使用说明测试使用harbor私有镜像仓库从harbor仓库下载镜像 Harbor介绍 容器应用的开发和运行离不开可靠的 镜像管理&…

STM32 CAN的工作模式

STM32 CAN的工作模式 正常模式 正常模式下就是一个正常的CAN节点&#xff0c;可以向总线发送数据和接收数据。 静默模式 静默模式下&#xff0c;它自己的输出端的逻辑0数据会直接传输到它自己的输入端&#xff0c;逻辑1可以被发送到总线&#xff0c;所以它不能向总线发送显性…

linux centos 安装jenkins,并构建spring boot项目

首先安装jenkins&#xff0c;使用war包安装&#xff0c;比较简单&#xff0c;注意看下载的版本需要的JDK版本&#xff0c;官网下载https://www.jenkins.io/download/ 把下载好的war包放到服务器上&#xff0c;然后运行&#xff0c;注意8080端口的放行 # 前台运行并指定端口 ja…

智能优化算法 | Matlab实现PID搜索算法(PSA)(内含完整源码)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现PID搜索算法(PSA)(内含完整源码) 源码设计 %%%% clc clear close all %%%% Fun_name=F12; % Fun_name of

后端Jwt实现Token编码、解码以及axios的request请求头的Token传输方式

目录 一、什么是JWT&#xff1a; 二、Jwt的使用&#xff1a; 第一步&#xff1a;引入依赖&#xff1a; 第二步&#xff1a;配置拦截器&#xff1a;JwtInterceptor.java&#xff1a; 其中异常文件ServiceException配置如下&#xff1a; 全局异常文件GlobalException.java文…

海康威视-AIOT的业务转型

海康威视的转型和定位为智能物联网&#xff08;AIoT&#xff09;解决方案和大数据服务的提供商。 公司不仅仅聚焦于其核心的视频监控业务&#xff0c;而且正在积极拓展到新的技术领域和市场。通过专注于物联感知、人工智能、大数据等技术的创新&#xff0c;对未来技术发展方向的…

增强现实(AR)在广告中的力量

The Power of AR in Advertising 写在前面 增强现实&#xff08;AR -Augmented Reality&#xff09;是指借助软件、应用程序和智能手机、平板电脑或耳机等设备&#xff0c;为日常生活添加视觉和音频元素的技术。如今&#xff0c;品牌和广告商可以在营销活动中使用AR&#xff0…

车道线检测论文:《Ultra Fast Structure-aware Deep Lane Detection》

该论文标题为《Ultra Fast Structure-aware Deep Lane Detection》&#xff0c;作者是浙江大学计算机科学与技术学院的Zequn Qin、Huanyu Wang和Xi Li。论文提出了一种新颖的、简单而有效的车道检测方法&#xff0c;旨在解决具有挑战性场景下的车道检测问题&#xff0c;并实现极…

CentOS系统部署YesPlayMusic播放器并实现公网访问本地音乐资源

文章目录 1. 安装Docker2. 本地安装部署YesPlayMusic3. 安装cpolar内网穿透4. 固定YesPlayMusic公网地址 本篇文章讲解如何使用Docker搭建YesPlayMusic网易云音乐播放器&#xff0c;并且结合cpolar内网穿透实现公网访问音乐播放器。 YesPlayMusic是一款优秀的个人音乐播放器&am…

idea使用token方式登录GitHub

总体上分为两大步&#xff1a;1.GitHub生成token。2.idea配置token登录GitHub。 注&#xff1a;idea配置GitHub的前提是本地已经安装了git程序。 一、GitHub生成token 1.登录GitHub 2.进入token创建页面&#xff08;右上角点击头像–>settings–>页面向下滚动左侧菜单栏…

网络上常见的环路指的是什么

人类的创造力与破坏力同样强大"。 网路互通&#xff0c;同样也衍生出纷繁复杂的路由协议和各种因特网服务&#xff0c;以及"网络安全"这个庞大的领域。 这也是为什么说当今所有的网络通讯流量中&#xff0c;80%的资源都被浪费&#xff0c;只有20%被用以有效数…

网络安全实训Day8

写在前面 网络工程终于讲完了。这星期到了网络安全技术部分。 网络安全实训-网络安全技术 网络安全概述 信息安全&#xff1a;所有保障计算机硬件、系统、软件、数据不因有意或无意的行为导致的服务中断、数据损坏或丢失等安全事件的保障技术 网络安全&#xff1a;基于计算机…