题意:
给出1到n这n个数的任意一个排列,然后奇数按顺序分到o数组,偶数按顺序分到e数组,你每次可以询问e数组中第i个和o数组中第j个的大小情况,查询结束后输出结果,查询次数最多30 000次,
思路:
我们先想,如果e是有序的,那么我们就可以枚举奇数组中每个数字,然后每次都二分,次数为
。但是此时e是无序的,所以我们要想办法让e变得有序来减少询问次数。
我们先用o数组中的数
,和e数组中每个数字比较关系,查询
次,会发现,我们不仅确定了这个数字的大小,也将e数组切成了两块(一块里面的数字都比x小,一块里面数字都比x大,块内数字无序)。
按照这个方法接着向下做,我们会发现,对于每个奇数,我们能利用这个奇数把某一个偶数块切成两块,这样我们最后会把偶数切成n/2块,也就确定了每个偶数的大小。这样我们就能
枚举得到结果。
可是询问次数不允许,我们不能
枚举。我们发现偶数块其实也是具有一定的单调性的(虽然内部无序),我们可以用偶数块中某一个数字代表这个块,每次奇数查询的时候利用这个数字进行二分,二分就可以找到第一个代表值大于当前奇数的偶数块,这块以及前面一块都是有可能的(因为块内部是无序的),然后遍历两个块才能判断出到底需要的是哪一块。
这种做法最差情况下询问次数是
的,但是题目保证数据是随机的,所以可以当作是
的,而且因为n才1000,时间却有10秒,所以怎么随意暴力都是可以的
错误及反思:
边界处理需要特判
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 11000;
int ans1[N],ans2[N],n,tot=1;
vector<int> v[N];
int change(int p,int x){
int ans=0;
for(int i=1;i<p;i++)
ans+=v[i].size();
vector<int> vv[2];
for(int i=0;i<v[p].size();i++){
printf("? %d %d\n",v[p][i],x);
fflush(stdout);
char t[10]; scanf("%s",t);
if(t[0]=='<'){
ans++;
vv[0].push_back(v[p][i]);
}
else vv[1].push_back(v[p][i]);
}
if(vv[0].size()&&vv[1].size()){
tot++;
for(int i=tot;i>p;i--) v[i]=v[i-1];
v[p]=vv[0];
v[p+1]=vv[1];
}
else if(vv[1].size()==0){
return n%2?n:n-1;
}
else if(p==1){
return 1;
}
else{
p--;
ans=0;
vv[0].clear(); vv[1].clear();
for(int i=1;i<p;i++)
ans+=v[i].size();
for(int i=0;i<v[p].size();i++){
printf("? %d %d\n",v[p][i],x);
fflush(stdout);
char t[10]; scanf("%s",t);
if(t[0]=='<'){
ans++;
vv[0].push_back(v[p][i]);
}
else vv[1].push_back(v[p][i]);
}
tot++;
for(int i=tot;i>p;i--) v[i]=v[i-1];
v[p]=vv[0];
v[p+1]=vv[1];
}
return ans*2+1;
}
int main(){
scanf("%d",&n);
if(n==1){
puts("! 1\n");
fflush(stdout);
return 0;
}
if(n==2){
puts("! 2 1\n");
fflush(stdout);
return 0;
}
for(int i=1;i<=n/2;i++) v[1].push_back(i);
for(int i=1;i<=(n+1)/2;i++)
{
int l=0,r=tot;
while(l+1<r){
int m=(l+r)/2;
printf("? %d %d\n",v[m][0],i);
fflush(stdout);
char t[10]; scanf("%s",t);
if(t[0]=='<') l=m;
else r=m;
}
ans1[i]=change(r,i);
}
for(int i=1;i<=n/2;i++)
ans2[v[i][0]]=i*2;
printf("!");
for(int i=1;i<=n/2;i++) printf(" %d",ans2[i]);
for(int i=1;i<=(n+1)/2;i++) printf(" %d",ans1[i]);
puts("");
fflush(stdout);
}