题解:P12428 [BalticOI 2025] Tower
很抽象的题目。
首先看到评分标准是所有测试用例的平均次数而不是最大次数与数据随机生成,考虑随机化做法。
对于一个初始的长度为
三类点都构成圆的一段弧,但是第三类点可能构成优弧,这是我们不希望看到的,因为处理优弧上问题时可能出现两个优弧上的点最短路径不在优弧上的情况,考虑合理的选择
不难发现不出现第三类点(或者第三类点只包含一个单独的点)的充要条件是
考虑这样一个算法:先随机选取一对
实际上问出一组满足条件的
询问次数大概是
由于某些原因写代码的过程比较曲折,所以代码未必能看。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 600;
mt19937 rd(114514);
int n;
vector<int> X,Y;
int r;
map< pair<int,int>,vector< pair<int,int> > > dp[maxn];
void ask(int a,int b,int c){
vector<int> so;
so.resize(3);
so[0]=a,so[1]=b,so[2]=c;
sort(so.begin(),so.end());
a=so[0],b=so[1],c=so[2];
if(dp[a].find(make_pair(b,c))!=dp[a].end()){
r=0;
X.clear();
Y.clear();
vector< pair<int,int> > res=dp[a][make_pair(b,c)];
r=res.size();
X.resize(r),Y.resize(r);
for(int i=0;i<r;i++){
X[i]=res[i].first,Y[i]=res[i].second;
}
return ;
}
cout<<"? "<<a<<" "<<b<<" "<<c<<endl;
r=0;
X.clear();
Y.clear();
cin>>r;
X.resize(r),Y.resize(r);
vector< pair<int,int> > res;
for(int i=0;i<r;i++){
cin>>X[i]>>Y[i];
res.push_back(make_pair(X[i],Y[i]));
}
dp[a][make_pair(b,c)]=res;
}
bool check(int a,int b,int c,int d){
return max(a,b)==max(c,d)&&min(a,b)==min(c,d);
}
bool chk(int a,int b,int c){
ask(a,b,c);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
for(pair<int,int> now:ans){
if(check(now.first,now.second,a,b)==true) return true;
}
return false;
}
int cnt=0;
vector<int> solve(vector<int> vec){
if(vec.size()==3){
ask(vec[0],vec[1],vec[2]);
vector<int> res;
if(Y[0]!=X[1]&&Y[0]!=Y[1]) swap(X[0],Y[0]);
res.push_back(X[0]);
res.push_back(Y[0]);
if(X[1]!=Y[0]) swap(X[1],Y[1]);
res.push_back(Y[1]);
return res;
}
if(vec.size()<=2) return vec;
shuffle(vec.begin(),vec.end(),rd);
int u=vec[0],v=vec[1];
vector<int> L1,L2;
L1.push_back(u);
L2.push_back(v);
int cut=-1;
vector<int> res;
for(int i:vec){
if(i!=u&&i!=v){
ask(u,v,i);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
for(pair<int,int> now:ans){
if(check(now.first,now.second,u,v)==true) return res;
}
assert(ans.size()<=2);
if(ans.size()==2) cut=i;
else{
if(check(ans[0].first,ans[0].second,u,i)==true) L1.push_back(i);
else L2.push_back(i);
}
}
}
vector<int> Vec=vec,l1=L1,l2=L2;
sort(Vec.begin(),Vec.end());
sort(l1.begin(),l1.end());
sort(l2.begin(),l2.end());
while(1){
vector<int> res=solve(L1);
if(res.size()==L1.size()){
L1=res;
break;
}
}
while(1){
vector<int> res=solve(L2);
if(res.size()==L2.size()){
L2=res;
break;
}
}
for(int x:L1){
if(x==cut) assert(0);
}
for(int x:L2){
if(x==cut) assert(0);
}
if(cut==-1){
if(L2.size()<L1.size()) swap(L1,L2);
ask(L1[0],L1.back(),L2[0]);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
bool flag=false;
for(pair<int,int> now:ans){
if(check(now.first,now.second,L1[0],L2[0])==true) flag=true;
if(check(now.first,now.second,L1.back(),L2[0])==true) flag=true;
}
if(flag==false){
ask(L1[0],L1.back(),L2.back());
ans.clear();
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
if(check(ans[0].first,ans[0].second,L1[0],L2.back())==true){
for(int u:L2) res.push_back(u);
for(int u:L1) res.push_back(u);
return res;
}else{
reverse(L1.begin(),L1.end());
for(int u:L2) res.push_back(u);
for(int u:L1) res.push_back(u);
return res;
}
}else{
if(check(ans[0].first,ans[0].second,L1[0],L2[0])==true){
reverse(L2.begin(),L2.end());
for(int u:L2) res.push_back(u);
for(int u:L1) res.push_back(u);
return res;
}else{
for(int u:L1) res.push_back(u);
for(int u:L2) res.push_back(u);
return res;
}
}
}else{
if(L1.size()>L2.size()) swap(L1,L2);
if(L1.size()==1){
if(L2.size()==1){
res.push_back(L1[0]);
res.push_back(cut);
res.push_back(L2[0]);
return res;
}else{
if(chk(cut,L2[0],L2[1])==true){
res.push_back(L1[0]);
res.push_back(cut);
for(int x:L2) res.push_back(x);
return res;
}else{
reverse(L2.begin(),L2.end());
res.push_back(L1[0]);
res.push_back(cut);
for(int x:L2) res.push_back(x);
return res;
}
}
}
if(chk(cut,L1[0],L1[1])==true){
if(chk(cut,L2[0],L2[1])==true){
reverse(L2.begin(),L2.end());
for(int u:L2) res.push_back(u);
res.push_back(cut);
for(int u:L1) res.push_back(u);
return res;
}else{
for(int u:L2) res.push_back(u);
res.push_back(cut);
for(int u:L1) res.push_back(u);
return res;
}
}else{
reverse(L1.begin(),L1.end());
if(chk(cut,L2[0],L2[1])==true){
reverse(L2.begin(),L2.end());
for(int u:L2) res.push_back(u);
res.push_back(cut);
for(int u:L1) res.push_back(u);
return res;
}else{
for(int u:L2) res.push_back(u);
res.push_back(cut);
for(int u:L1) res.push_back(u);
return res;
}
}
}
return res;
}
int p[maxn],x,y;
vector<int> build(){
for(int i=0;i<n;i++) p[i]=i;
shuffle(p,p+n,rd);
x=p[0],y=p[1];
for(int i=2;i<n;i++){
if(x==y||x==p[i]||y==p[i]){
assert(0);
}
ask(x,y,p[i]);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
if(ans.size()==1&&check(ans[0].first,ans[0].second,x,y)==true) y=p[i];
}
vector<int> res;
vector<int> L1,L2;
L1.push_back(x);
L2.push_back(y);
vector<int> cut;
for(int i=0;i<n;i++){
if(i!=x&&i!=y){
ask(x,y,i);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
if(ans.size()==3||(ans.size()==2&&check(ans[0].first,ans[0].second,x,y)!=true&&check(ans[1].first,ans[1].second,x,y)!=true)){
cut.push_back(i);
}else if(ans.size()==1){
if(check(ans[0].first,ans[0].second,x,i)==true) L1.push_back(i);
else if(check(ans[0].first,ans[0].second,y,i)==true) L2.push_back(i);
else return res;
}else return res;
}
}
while(1){
vector<int> res=solve(L1);
if(res.size()==L1.size()){
L1=res;
break;
}
}
while(1){
vector<int> res=solve(L2);
if(res.size()==L2.size()){
L2=res;
break;
}
}
assert(L1.size()==L2.size());
if(cut.size()==2){
if(L1.size()==1){
res.push_back(L1[0]);
res.push_back(cut[0]);
res.push_back(L2[0]);
res.push_back(cut[1]);
return res;
}
if(chk(cut[0],L1[0],L1[1])==true){
reverse(L1.begin(),L1.end());
if(chk(cut[0],L2[0],L2[1])==true){
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
res.push_back(cut[1]);
}else{
reverse(L2.begin(),L2.end());
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
res.push_back(cut[1]);
}
}else{
if(chk(cut[0],L2[0],L2[1])==true){
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
res.push_back(cut[1]);
}else{
reverse(L2.begin(),L2.end());
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
res.push_back(cut[1]);
}
}
return res;
}else if(cut.size()==1){
if(L1.size()==1){
res.push_back(L1[0]);
res.push_back(cut[0]);
res.push_back(L2[0]);
return res;
}
if(chk(cut[0],L1[0],L1[1])==true){
reverse(L1.begin(),L1.end());
if(chk(cut[0],L2[0],L2[1])==true){
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
}else{
reverse(L2.begin(),L2.end());
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
}
}else{
if(chk(cut[0],L2[0],L2[1])==true){
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
}else{
reverse(L2.begin(),L2.end());
for(int x:L1) res.push_back(x);
res.push_back(cut[0]);
for(int x:L2) res.push_back(x);
}
}
return res;
}else{
if(L1.size()==1){
res.push_back(L1[0]);
res.push_back(L2[0]);
return res;
}
ask(L1[0],L1.back(),L2[0]);
vector< pair<int,int> > ans;
ans.resize(r);
while(r--) ans[r].first=X[r],ans[r].second=Y[r];
for(pair<int,int> now:ans){
if(check(now.first,now.second,L2[0],L1[0])==true){
reverse(L1.begin(),L1.end());
for(int x:L1) res.push_back(x);
for(int x:L2) res.push_back(x);
return res;
}
if(check(now.first,now.second,L2[0],L1.back())==true){
for(int x:L1) res.push_back(x);
for(int x:L2) res.push_back(x);
return res;
}
}
}
return res;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t,k;
cin>>t>>k;
for(int i=1;i<=t;i++){
cin>>n;
while(1){
vector<int> res=build();
if(res.size()==n){
cout<<"! ";
for(int i=0;i<n;i++){
cout<<res[i];
if(i!=n-1) cout<<" ";
}
cout<<endl;
break;
}
}
for(int j=0;j<n;j++) dp[j].clear();
}
return 0;
}