CF1167B题解
原题
思路概述
题意分析
给定一个由 \(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;
}
浙公网安备 33010602011771号