2 条题解
-
0
怎么没题解呢,那就发一篇吧。
首先考虑有 3 个位置,标号为 ,两两询问得到 。 三个值中一定有两个相等,且这个值是三数中最小的数。又因为所有值互不相等,所以可以确定最小值的位置(例如如果 那么最小值位置在 处)。
现在有前缀最大值 和次大值 和 ,每次新加入一个 就可以通过两次询问确定一个值。
但是这样的构造操作次数是 的,无法通过。考虑丧失了哪些性质。对于某些 不需要询问两次,如果询问得到的结果 小于前缀次大值,那么三数中最小值是 且位置在 。
所以现在次数为 。序列前缀最大值个数期望是 ,那么前缀次大值期望个数小于 (期望 个数更新前缀最大值时次大值被更新,又期望 个数可能更新次大值),可以通过本题。
注意要打乱序列。
#include<bits/stdc++.h> using namespace std; const int N = 2000; int n,a[N],ans[N]; inline int ask(int x,int y) { int tmp; cout<<"? "<<x<<' '<<y<<endl; cin>>tmp; return tmp; } int x,y,xx,yy,zz; bool t; inline void work(int z) { yy=ask(x,z); if(yy<xx) { ans[z]=yy; return; } zz=ask(y,z); if(xx==yy) ans[x]=xx,x=z,xx=zz; else if(yy==zz) ans[z]=yy; else//xx==zz ans[y]=xx,y=z,xx=yy; } mt19937 rd(time(0)); signed main() { cin>>n; for(int i=1;i<=n;i++)a[i]=i; if(n==2) { int tmp=ask(1,2); ans[1]=ans[2]=tmp; } else { shuffle(a+1,a+1+n,rd); x=a[1],y=a[2]; xx=ask(a[1],a[2]); for(int i=3;i<=n;i++) work(a[i]); int tmp=max({xx,yy,zz}); ans[x]=ans[y]=tmp; } cout<<"! "; for(int i=1;i<=n;i++)cout<<ans[i]<<' '; cout<<endl; } -
0
这么变态吗?
首先题目中的 给我们一个启发,就是一个位置最多需要两次查询得到。
这样,我们直接考虑对于三个不同的位置,假设不知道它们的值的情况下怎么两次出答案:
我们这样查询:,设第一个值为 ,第二个值为 ,不难做下面的分类讨论(前提是 互不相同):
- :即 ,如果前面一个是 ,后一个如果是 都会与 中元素互不相同冲突,所以一定是 ;
- :即 ,如果前面一个是 ,如果后一个是 ,则与大于号矛盾,所以此时可以确定 ,而对于前面一个是 ,则后面一个同样是 。
- :不难用 的逻辑,推出此时确定 。
如此,就可以获得一共 分。
然后对于那个 次以内,猜测是较松的 ,先使用记忆化,发现有一定的点通过,然后考虑到记忆化以后,次数做到 加前缀最大值个数。
所以套上随机化一遍,此时期望在 左右,容易通过。
- 1
信息
- ID
- 7349
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者