zoukankan      html  css  js  c++  java
  • 【ECNU3542】神奇的魔术(二分交互题)

    点此看题面

    大致题意: 有一个(1sim 2^n)的排列,(nle7),每次交互告诉你有几个位置上的数是正确的,让你在(1000)轮以内猜出每个位置上的数。

    二分

    显然,我们可以通过二分来求解此题。

    具体地,我们先把所有位置填满(1),然后暴力枚,找到一个位置填上(2)使得此时没有一个位置上的数是正确的。

    然后接下来,我们枚举(3sim2^n)的每一个数,每次把(lsim mid)这段区间内除不是(1)(2)的位置外全填上当前数,然后询问当前对的数的个数。

    最后我们交换序列中的(1)(2)即可。

    但注意这样次数会超,于是要加上一个小优化,即若当前二分到的区间内全填满了不是(1)(2)的数,就直接返回(false)

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 7
    using namespace std;
    int n,bit,a[(1<<N)+5],b[(1<<N)+5],g[(1<<N)+5];
    I void Print() {for(RI i=1;i<=bit;++i) cout<<a[i]<<" ";cout<<endl;}//输出交互
    I bool Check(CI x,CI tl,CI tr)//检查
    {
    	RI i,t,fg=0;for(i=tl;i<=tr;++i) a[i]==b[i]&&(a[i]=x,fg=1);
    	if(!fg) return 0;Print(),cin>>t;if(!~t) return 20030909;
    	for(i=tl;i<=tr;++i) a[i]==x&&(a[i]=b[i]);return t==x-2;
    }
    int main()
    {
    	RI i,t=0,l,r,mid;for(cin>>n,bit=1<<n,i=1;i<=bit;++i) a[i]=b[i]=1;bit==2&&(g[1]=1,g[2]=2);
    	for(i=1;i<=(bit>>2);++i) g[++t]=(bit>>1)-i+1,g[++t]=(bit>>1)+i,g[++t]=i,g[++t]=bit-i+1;
    	for(i=1;i<=bit;++i) if(a[g[i]]=2,Print(),cin>>t,t==0) {b[g[i]]=2;break;}else a[g[i]]=1;//初始化
    	for(i=3;i<=bit;++i)//枚举数
    	{
    		l=1,r=bit;W(l<r) Check(i,l,mid=l+r-1>>1)?r=mid:l=mid+1;//二分
    		a[r]=i;//填数
    	}
    	for(i=1;i<=bit;++i) a[i]==1?a[i]=2:a[i]==2&&(a[i]=1);return Print(),0;//输出
    }
    
  • 相关阅读:
    【WP开发】WebView控件应用要点
    【WP开发】认清“不透明度”与“可见性”的区别
    分享:自学编程的方法
    <C#>找出数组中重复次数最多的数值
    【WP 8.1开发】上下文菜单
    【WP 8.1开发】同时更新多种磁贴
    【WP开发】如何处理溢出的文本
    lnmp/nginx系统真正有效的图片防盗链完整设置详解
    PHP自动加载SPL的四种处理方式
    算法笔记-判断链表保存的字符串是否是回文
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/ECNU3542.html
Copyright © 2011-2022 走看看