题解:CF2134E Power Boxes

原题链接

分享图片
 2025-08-27 094622.png

解析

首先小心不要把“总跳跃次数”看成“总跳跃长度”。

如果你做过前一场的 E,那么你应该很快能想到要把 \(\lceil \frac{3n}{2} \rceil\) 变成 \(n + \lceil \frac{n}{2} \rceil\)

手玩一下,发现如果设 \(s_i\) 表示从 \(i\) 开始跳的总跳跃次数,当 \(s_{i + 1} \not= s_{i + 2}\) 时,可以通过 \(\texttt{throw } i\) 确定 \(a_i\)\(s_i\) 的值;而当 \(s_{i + 1} = s_{i + 2}\) 时,虽然无法直接确定 \(a_i\) 的值,但是可以得知 \(s_i = s_{i + 1} + 1\)

这样扫一遍过后,在任意相邻的 \(3\) 个位置上,\(s\) 至少有 \(2\) 种不同的取值。这也意味着对于任意相邻的两个位置,未知的 \(a\) 至多有 \(1\) 个。

太好了,这不就跟 \(\lceil \frac{n}{2} \rceil\) 对上了嘛。于是我们来尝试在两次操作以内求出一个未知的 \(a\)。对于一个位置 \(i\),如果 \(a_i\) 是未知的,那么有 \(s_{i + 1} = s_{i + 2}\)\(a_{i + 1} = 2\)。利用这个性质,只需先 \(\texttt{swap } i\)\(\texttt{throw } i+1\),若得到 \(s_{i + 1}\),则说明 \(a_i=2\),否则 \(a_i=1\)。正着扫一遍就可以求出除 \(a_n\) 外所有的值。

\(a_n\) 的方法想必你已经手玩出来了,这里不多赘述。

代码

由于我第二次是倒着扫的,所以还要维护交换后的 \(s\)\(a\),并且需要处理交换导致的对于一个 \(a\) 未知的位置 \(s_{i + 1} \not= s_{i + 2}\) 的情况,换个顺序进行操作可以规避这些问题。

/*
*/
#include<bits/stdc++.h>
#define eps 0.000001
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<ll,int> pii;
const int N = 2e5 + 5,M = 3.2e4 + 5;
ll a[N],stp[N],val[N],vis[N];
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out1.txt","w",stdout);
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		stp[n] = 1;
		int x;
		cout<<"throw "<<n - 1<<endl;
		cin>>x;
		a[n - 1] = x ^ 3;
		cout<<"swap "<<n - 1<<endl;
		cout<<"throw "<<n - 1<<endl;
		cin>>x;
		a[n] = x ^ 3;
		val[n - 1] = a[n],val[n] = a[n - 1];
		stp[n - 1] = x;
		stp[n + 1] = 0;
		for(int i=n - 2;i>=1;i--){
			if(stp[i + 1] != stp[i + 2] && stp[i + 2]){
				int x;
				cout<<"throw "<<i<<endl;
				cin>>x;
				stp[i] = x;
				if(x == stp[i + 2] + 1) a[i] = 2;
				else a[i] = 1;
				val[i] = a[i];
			}else{
				stp[i] = stp[i + 1] + 1;
			}
		}
		for(int i=n - 2;i>=1;i--){
			if(!a[i]){
				if(stp[i + 1] != stp[i + 2]){
					int x;
					cout<<"throw "<<i<<endl;
					cin>>x;
					stp[i] = x;
					if(x == stp[i + 2] + 1) a[i] = 2;
					else a[i] = 1;
					val[i] = a[i];
					continue;
				}
				int x,y;
				x = stp[i + 1];		
				cout<<"swap "<<i<<endl;
				cout<<"throw "<<i + 1<<endl;
				cin>>y;
				val[i] = val[i + 1];
				val[i + 1] = a[i] = y == x ? 2 : 1;
				stp[i + 1] = y;
				stp[i] = stp[i + val[i]] + 1;
			}else{
				stp[i] = stp[i + a[i]] + 1;
			}
		}
		cout<<"! "; 
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
			a[i] = stp[i] = val[i] = 0;
		}
		cout<<endl;
	} 
	return 0;
}
/*
*/
posted @ 2025-08-27 13:33  yutar  阅读(25)  评论(0)    收藏  举报