LGP14319 「ALFR Round 11」C1 开关灯 (switch) (ez ver.)

在我的博客园中查看本文

注意到题目的关键性质“损坏的灯泡不会连续两次取反”,所以可以通过至多两次操作能让这个灯泡“与众不同”。具体地,考虑在 \([1,n]\) 操作一次,此时调用一次查询 \([1,n]\) 可能会查出 \(n-1\) 盏或 \(n\) 盏亮的灯。如果是 \(n\) 个,那么就考虑再 \([1,n]\) 翻转一次,此时 \([1,n]\) 中只可能有一盏亮着的灯。

  • 如果是第一次查出 \(n-1\),那么就直接开始二分查找灭的那一盏;
  • 否则,就再集体翻转一次,然后查找亮的那一盏。

这样只需 \(2 \sim 3\) 次操作再加上 \(O(\log n)\) 次二分查找就可以查出来了,可以通过。

笑点解析:没看到多测 WA 了两发(

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int N=-1;
int n,tmp;
void operate(int l,int r){cout<<"1 "<<l<<' '<<r<<endl;}
int ask(int l,int r){cout<<"2 "<<l<<' '<<r<<endl;cin>>tmp;return tmp;}
void answer(int x){cout<<"3 "<<x<<endl;}
void solve()
{
	cin>>n;
	operate(1,n);
	int res=ask(1,n);
	if(res==n-1)  //这一次已经让坏灯暴露出来,二分查找
	{
		int l=1,r=n;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(ask(l,mid)==mid-l+1) l=mid+1;
			else r=mid;
		}
		answer(l);
	}
	else  //这一次还没暴露,再关一次
	{
		operate(1,n);
		int l=1,r=n;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(ask(l,mid)==0) l=mid+1;
			else r=mid;
			// cerr<<l<<' '<<r<<'\n';
		}
		answer(l);
	}
}
int main()
{
//	freopen("neuvillette.in","r",stdin);
//	freopen("neuvillette.out","w",stdout);
	int T; cin>>T;
	while(T--) solve();
	return 0;
}
posted @ 2026-08-14 21:33  wwwidk1234  阅读(2)  评论(0)    收藏  举报