维护两个集合\(S\)和\(T\),表示当前最后一个询问正确/错误时可能的答案
初始\(S=[1,10^{9}]\)且\(T=\empty\),每次划分\(\begin{cases}S=S_{1}\cup S_{2}\\ T=T_{1}\cup T_{2}\end{cases}\),并返回\([x\in S_{1}\cup T_{1}]\)
若收到\(1\),则\(\begin{cases}S'=S_{1}\cup T_{1}\\T'=S_{2}\end{cases}\),收到\(0\)类似,并用区间的形式存储即可
取\(|S_{1}|=\lceil\frac{|S|}{2}\rceil,|T_{1}|=\lfloor\frac{|T|}{2}\rfloor\),则\(\begin{cases}|S'|\le \lceil\frac{|S|+|T|}{2}\rceil\\|T'|\le \lceil\frac{|S|}{2}\rceil\end{cases}\)
事实上,这样的策略并不一定最优,因此在\(|S|\)和\(|T|\)较小时可以dp求出最优解
经计算,\(80\)轮后有\(|S|+|T|<50\),此时dp求出至多\(17\)次,总次数\(\le 97\)
#include<bits/stdc++.h>
#include "communication.h"
using namespace std;
#define fi first
#define se second
typedef pair<int,int> pii;
const int N=50;
int s,t,f[N][N],fI[N][N],fJ[N][N];
struct Node{
int sz;
vector<pii>v;
Node(){
sz=0,v.clear();
}
Node(int n){
sz=n;
v=vector<pii>{make_pair(1,n)};
}
}S,T,S1,S2,T1,T2;
Node merge(Node x,Node y){
Node k;
k.sz=x.sz+y.sz;
for(pii i:x.v)k.v.push_back(i);
for(pii i:y.v)k.v.push_back(i);
return k;
}
void divide(Node k,int s,Node &x,Node &y){
x=Node(),y=Node();
x.sz=s,y.sz=k.sz-s;
for(pii i:k.v){
int l=i.se-i.fi+1;
if (!s)y.v.push_back(i);
else{
if (s>=l)x.v.push_back(i),s-=l;
else{
x.v.push_back(make_pair(i.fi,i.fi+s-1));
y.v.push_back(make_pair(i.fi+s,i.se));
s=0;
}
}
}
}
void init(){
memset(f,0x3f,sizeof(f));
for(int s=0;s<N;s++)
for(int i=0;i<=s;i++){
int j=s-i;
if (s<3){f[i][j]=0;continue;}
for(int I=0;I<=i;I++)
for(int J=0;J<=j;J++){
if (f[i][j]>max(f[I+J][i-I],f[i+j-I-J][I])+1){
fI[i][j]=I,fJ[i][j]=J;
f[i][j]=max(f[I+J][i-I],f[i+j-I-J][I])+1;
}
}
}
}
void encode(int n,int x){
init(),S=Node(n),T=Node();
while (S.sz+T.sz>2){
if (S.sz+T.sz<N)s=fI[S.sz][T.sz],t=fJ[S.sz][T.sz];
else s=(S.sz+1>>1),t=(T.sz>>1);
divide(S,s,S1,S2),divide(T,t,T1,T2);
bool flag=0;
for(pii i:S1.v)
if ((i.fi<=x)&&(x<=i.se))flag=1;
for(pii i:T1.v)
if ((i.fi<=x)&&(x<=i.se))flag=1;
if (send(flag))S=merge(S1,T1),T=S2;
else S=merge(S2,T2),T=S1;
}
}
pair<int,int> decode(int n){
init(),S=Node(n),T=Node();
while (S.sz+T.sz>2){
if (S.sz+T.sz<N)s=fI[S.sz][T.sz],t=fJ[S.sz][T.sz];
else s=(S.sz+1>>1),t=(T.sz>>1);
divide(S,s,S1,S2),divide(T,t,T1,T2);
if (receive())S=merge(S1,T1),T=S2;
else S=merge(S2,T2),T=S1;
}
int x=0,y=0;
for(pii i:S.v)
for(int j=i.fi;j<=i.se;j++){
if (!x)x=j;
else y=j;
}
for(pii i:T.v)
for(int j=i.fi;j<=i.se;j++){
if (!x)x=j;
else y=j;
}
if (!y)y=x;
return make_pair(x,y);
}
标签:Node,sz,Flight,int,S1,back,Ford,qoj4208,fi
From: https://www.cnblogs.com/PYWBKTDA/p/17069216.html