题解:P14319 「ALFR Round 11」C1 开关灯 (switch) (ez ver.)

· · 题解

题意

n 个灯泡,这 n 个灯泡中含有一个损坏的灯泡,这些灯泡初始时都是暗的,你可以进行反转 l \sim r,查询 l \sim r 之间亮的灯泡的数量两个操作。

思路

注意到损坏的灯泡每次有概率反转,但反转不会连续进行两次,因此可以分为两种情况讨论。

对于第一种情况,我们对其进行二分,对于每个 l \sim mid 若这个区间没有损坏的灯泡,则其应当有 mid-l+1 个亮的灯泡,将 l 设为 mid+1

对于第二种情况,先将其进行反转,此时由于损坏灯泡不能连续两次反转,1 \sim n 范围内应当有 1 个亮的灯泡,此灯泡为损坏的灯泡,二分求出损坏灯泡的位置。

最多操作次数为 \log(n)+3 次,不超过限制。

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        cout<<"1 1 "<<n<<endl;
        cout<<"2 1 "<<n<<endl;
        int now;
        cin>>now;
        if(now!=n) //损坏灯泡未反转
        {
            int l=1,r=n,ans=0;
            while(l<=r)//二分查询损坏灯泡
            {
                int mid=l+((r-l)>>1);
                cout<<"2 "<<l<<' '<<mid<<endl;
                int a;
                cin>>a;
                if(a!=mid-l+1)
                {
                    ans=mid;
                    r=mid-1;
                }
                else
                {
                    l=mid+1;
                }
            }
            cout<<"3 "<<ans<<endl;
        }
        else //损坏灯泡在第一次操作反转
        {
            cout<<"1 1 "<<n<<endl;//再次反转,此时只有一个亮的灯泡即为损坏灯泡
            int l=1,r=n,ans=0;
            while(l<=r)
            {
                int mid=l+((r-l)>>1);
                cout<<"2 "<<l<<' '<<mid<<endl;
                int a;
                cin>>a;
                if(a!=0)
                {
                    ans=mid;
                    r=mid-1;
                }
                else
                {
                    l=mid+1;
                }
            }
            cout<<"3 "<<ans<<endl;
        }
    }
    return 0;
}