ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CF1491F]Magnets

2021-05-16 11:32:23  阅读:185  来源: 互联网

标签:磁铁 int rep CF1491F 磁石 sec Magnets 2n


[CF1491F]Magnets

壹、题目描述 ¶

传送门 to CF.

官方题面

这是一个交互题。

早苗有 \(n\) 块磁石,编号为 \(1,2,\cdots,n\). 每块磁石的磁极可能是正极,负极,也可能没有磁性。她希望你能帮她找出所有没有磁性的磁石。

万幸的是,你有一台磁力检测仪。你每次可以将每个磁石放在这台机器的左托盘,右托盘或者不放。

机器将会返回此时的磁力强度。设托盘左边有 \(n_1\) 个磁石为正极,\(s_1\) 个磁石为负极,托盘右边中有 \(n_2\) 磁石为正极,\(s_2\) 个磁石为负极,则返回的磁力强度为 \(n_1n_2+s_1s_2-n_1s_2-n_2s_1\).

如果一次测试中磁力强度的绝对值大于 \(n\),这台机器就会坏掉。

你需要在 \(n+\lfloor\log_2n\rfloor\) 次测试内找到所有没有磁性的磁石的编号,同时不能弄坏机器

贰、题解 ¶

真的是个妙妙题,本来以为是在 \(\log\) 的复杂度下找到带有磁性的磁铁......结果......倒打一耙......

不难发现,我们只需要找到一个带有磁性的磁铁,然后一个一个地试其他的磁铁,就可以得到所有退磁的磁铁。

接下来,给一些提示有助于你的思考:


Hint-1. 能否找到一种方法在 \(2n\) 次询问内解决问题?


Hint-2. 能否找到第二个带有磁性的磁铁?如何找?找到的时候发现了什么性质了吗?


Hint-3. 实际的询问上限是 \(n-1+\lceil \log_2n \rceil\).


题解

发现式子实际上就是 \((n_1-s_1)(n_2-s_2)\).

我们可以这样来找到一个我们想要的磁铁:

首先,我们把第一个磁铁放在机器左边,然后,把下一个(第二个)磁铁放在右边。

如果机器返回的是 \(0\),则说明左右两边一定有一个(或一堆)呈“电中性”,那么我们把放在右边的那个磁铁放到左边去,然后再把下一个放到右边去比较,递归这个过程。换句话说,对于磁铁 \(i=2,\cdots ,n\),我们依次询问 \([1,i-1]\) 与 \(i\) 磁铁的力大小。显然,这样询问不会让机器爆炸。

当某个时刻,发现有力了,我们就停止这个过程!显然,右边孤零零的第 \(i\) 个磁铁就一定“带电”了。

接下来我们就可以暴力一个一个地询问了!挨个从 \(1\) 问到 \(n\),但是这样我们需要花费 \(\mathcal O(2n)\) 的询问,这不好。

考察我们找到磁铁时刻的性质 —— 左边 \([1,i-1]\) 的磁铁当中,一定只有一个“带电”!

首先,因为有力,所以左边的一堆磁铁都肯定带电,其次,如果有大于等于两个磁铁带电,我们假设编号最小的两个磁铁编号为 \(j,k(1\le j<k<i)\),那么,当我们询问 \([1,k-1]\) 与 \(k\) 号磁铁时,机器返回的就肯定不是 \(0\),即我们在问到 \(k(k<i)\) 的时候就已经停止了,还和 \(i\) 有什么关系呢?

所以,我们只需要将 \([i+1,n]\) 的磁铁和 \(i\) 一个一个地问,找到“电中性”的,对于 \([1,i-1]\) 种藏着的那个带电磁铁,我们用二分来查找即可!

总共需要的询问次数 \(n-1+\lceil \log_2n \rceil\).

叁、参考代码 ¶

int n, sec;

vector<int>ans;

inline int query(int l1, int r1, int l2, int r2){
    printf("? %d %d\n", r1-l1+1, r2-l2+1);
    rep(i, l1, r1) printf("%d ", i); Endl;
    rep(i, l2, r2) printf("%d ", i); Endl;
    fflush(stdout);
    return readin(1);
}

signed main(){
    rep(tmp_fuck, 1, readin(1)){
        n=readin(1);
        rep(i, 2, n){
            int ret=query(1, i-1, i, i);
            if(ret){
                sec=i; break;
            }
        }
        ans.clear();
        int l=1, r=sec-1, mid, res;
        while(l<r){
            mid=(l+r)>>1;
            if(query(1, mid, sec, sec)) r=mid;
            else l=mid+1;
        }
        rep(i, 1, sec-1) if(i!=l)
            ans.push_back(i);
        rep(i, sec+1, n){
            int ret=query(sec, sec, i, i);
            if(!ret) ans.push_back(i);
        }
        printf("! %d", ans.size());
        for(int i: ans) printf(" %d", i);
        Endl; fflush(stdout);
    }
    return 0;
}

肆、用到 の Trick

不要被询问次数蒙蔽的双眼......遇到特殊时刻时,应该考察这个时刻可能存在的性质。

标签:磁铁,int,rep,CF1491F,磁石,sec,Magnets,2n
来源: https://www.cnblogs.com/Arextre/p/14773431.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有