1 条题解

  • 0
    @ 2025-8-24 23:07:49

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zzzyyyyhhhhh
    omori will become sunny

    搬运于2025-08-24 23:07:49,当前版本为作者最后更新于2025-01-04 19:49:14,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    怎么没题解呢,那就发一篇吧。

    首先考虑有 3 个位置,标号为 a,b,ca,b,c,两两询问得到 x=min{a,b},y=min{a,c},z=min{b,c}x=\min\{a,b\},y=\min\{a,c\},z=\min\{b,c\}x,y,zx,y,z 三个值中一定有两个相等,且这个值是三数中最小的数。又因为所有值互不相等,所以可以确定最小值的位置(例如如果 x=yx=y 那么最小值位置在 aa 处)。

    现在有前缀最大值 aa 和次大值 bbmin{a,b}\min\{a,b\},每次新加入一个 cc 就可以通过两次询问确定一个值。

    但是这样的构造操作次数是 2×n12\times n-1 的,无法通过。考虑丧失了哪些性质。对于某些 cc 不需要询问两次,如果询问得到的结果 xx 小于前缀次大值,那么三数中最小值是 xx 且位置在 cc

    所以现在次数为 O(n+前缀次大值个数)O(n+\texttt{前缀次大值个数})。序列前缀最大值个数期望是 lnn\ln n,那么前缀次大值期望个数小于 2×lnn2\times \ln n(期望 lnn\ln n 个数更新前缀最大值时次大值被更新,又期望 lnn\ln n 个数可能更新次大值),可以通过本题。

    注意要打乱序列。

    #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;
    }
    
    • 1

    信息

    ID
    11228
    时间
    1000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者