CF1167B题解

原题

CF1167B Lost Numbers


思路概述

题意分析

给定一个由 \(4,6,15,16,23,42\) 组成的,长度为 \(6\) 的排列,四次询问,每次询问两个下标上数的乘积。要求输出该排列。

思路分析

笔者先考虑到两个错误思路:一是分别枚举 \(a_i×a_i(i∈[1,6])\) ,即 \(a_i^2\) ,但这种思路需要六次询问,不满足本题要求;二是枚举 \(a_i×a_{i+1}(i∈[1,5])\) ,同样需要五次询问,不满足题意。

将该排列拆分为 \(a_1,a_2,a_3\)\(a_4,a_5,a_6\) 两段。对于每连续三个数字(以前三为例),我们只需要两次询问 \(a_1×a_2,a_2×a_3\) ,就可以确定这三个数字(具体过程可自行推导)。对于后三个数字同理。


算法实现

实现没啥难度,不多说


AC code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#define RI register int
using namespace std;
const int maxn=1e1+10;
int rev,f,s,t;
int ss[maxn],r[maxn]={0,4,8,15,16,23,42};
inline int query(int p1,int p2);
inline void print(void);
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	rev=query(1,2);
	for(RI i=1;i<=6;++i)
		for(RI j=i+1;j<=6;++j)
			if(r[i]*r[j]==rev)
			{
				ss[1]=r[i];r[i]=0;
				ss[2]=r[j];r[j]=0;
			}
	rev=query(2,3);
	for(RI i=1;i<=6;++i)
		if(r[i]*ss[1]==rev)
		{
			swap(ss[1],ss[2]);ss[3]=r[i];r[i]=0;
			break;
		}
		else if(r[i]*ss[2]==rev)
		{
			ss[3]=r[i];r[i]=0;
			break;
		}
	rev=query(4,5);
	for(RI i=1;i<=6;++i)
		for(RI j=i+1;j<=6;++j)
			if(r[i]*r[j]==rev)
			{
				ss[4]=r[i];r[i]=0;
				ss[5]=r[j];r[j]=0;
			}
	rev=query(5,6);
	for(RI i=1;i<=6;++i)
		if(r[i]*ss[4]==rev)
		{
			swap(ss[4],ss[5]);ss[6]=r[i];r[i]=0;
			break;
		}
		else if(r[i]*ss[5]==rev)
		{
			ss[6]=r[i];r[i]=0;
			break;
		}
	print();
	return 0;
}
inline int query(int p1,int p2)
{
	RI ret;
	cout << "? " << p1 << " " << p2 << endl;
	cin >> ret;
	return ret;
}
inline void print(void)
{
	cout << "! ";
	for(RI i=1;i<=6;++i) cout << ss[i] << " ";
	return;
}

posted @ 2022-06-11 10:23  UOB  阅读(97)  评论(0)    收藏  举报