[ARC154D]A+B>C?:交互题与经典算法的联系

[ARC154D] A + B > C ?

交互题。有一个未知的排列,你每次可以询问交互库 ? a b c,交互库会回答 pa+pb>pc 是否成立,请在 nlogn 次询问中得到排列。

有三个参数实际上并不好做,如果有两个参数,那就相当于重载了大于号的运算符,这样的话,我们用基于比较的 O(nlogn) 排序算法即可得到原排列。

如何把三个参数变成两个参数?我们习惯性地去找 1(因为通常 1 是好找的),因为 pa+1>pbpa>pb 是完全等价的,因为这是个排列。

1 的过程可以在 O(n) 时间内完成:只有 1 满足 1+1>pi 对所有 pi1 都不成立。我们不断用当前可能为 1 的位置和一个未知的位置去比较,可以用双指针扫一遍得到。

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
	char c=getchar();int h=0,tag=1;
	while(!isdigit(c)) tag=(c=='-'?-1:1),c=getchar();
	while(isdigit(c)) h=(h<<1)+(h<<3)+(c^48),c=getchar();
	return h*tag;
}
void fil(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
}
const int N=5e5+50;
int pos1;
bool cmp(int a,int b) { //[a<b]
	cout<<"? "<<a<<" "<<pos1<<" "<<b<<endl;
	string s;
	cin>>s;
	if(s=="Yes") {
		return 0;
	}else{
		return 1;
	}
}
int p[N];
void merge(int l,int r) {
	if(l==r) {
		return ;
	}
	int mid=(l+r>>1);
	merge(l,mid);merge(mid+1,r);
	vector<int>t;
	int j,k;
	for(j=l,k=mid+1;j<=mid&&k<=r;) {
		if(cmp(p[j],p[k])) t.push_back(p[j]),j++;
		else t.push_back(p[k]),k++;
	}
	if(j<=mid) for(;j<=mid;j++) {
		t.push_back(p[j]);
	} 
	if(k<=r) for(;k<=r;k++) t.push_back(p[k]);
	int cnt=0;
	for(int x:t) {
		p[cnt+l]=x;cnt++;
	}
}
int a[N];
int main(){
//	fil();
	int n=read();
	int _i=1;
	for(	int i=1,k=2;i<=n&&k<=n;k++) {
		_i=i;
		cout<<"? "<<i<<" "<<i<<" "<<k<<endl;
		string s;
		cin>>s;
		if(s=="Yes") {
			i=k;
		}else{
		}
		_i=i;
	}
	pos1=_i;
	for(int i=1;i<=n;i++) p[i]=i;
	merge(1,n);
	for(int i=1;i<=n;i++) a[p[i]]=i;
	cout<<"! ";for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	cout<<endl;
	
	return 0;
}

posted @   Apricity8211  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示