CF1363D 题解

CF1363D 题解

$\text{Description}$

有一个长度为 $n$ 的数组,给定 $n,k$ 和 $k$ 个互不相交的 $[1,n]\cap\N^+ $ 的子集,你需要通过不超过 $12$ 次的询问(每次询问这个数组任意一个子集的最大值),对每个给出的子集算出下标不在该子集内的数的最大值。

$n\le 1000$

$\text{Solution}$

首先分析互不相交的意义:一个元素至多在一个子集出现。

那么这个数组的最大值会成为所有不包含该元素的子集的答案,我们就只需求出那个包含最大元素的子集的答案(花费 $1$ 次)。

利用二分法求解该数组的最大值及其位置即可。

$\text{Code}$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<bits/stdc++.h>
#define REG register
using namespace std;

int T,n,k,M,M1,S;

vector<int> Subs[2005];
int Vis[2005];

inline void Init(){
memset(Vis,0,sizeof Vis),S=0;
for(REG int i=1;i<=k;++i) Subs[i].clear();
}

inline void Read(){
scanf("%d %d",&n,&k);
for(REG int i=1;i<=k;++i){
int c,tmp;scanf("%d",&c);
for(REG int j=1;j<=c;++j) scanf("%d",&tmp),Subs[i].push_back(tmp);
}
}

inline int Query(int l,int r){
putchar('?');printf(" %d",r-l+1);
for(REG int i=l;i<=r;++i) printf(" %d",i);
cout<<endl;int Ans;scanf("%d",&Ans);return Ans;
}

inline void GetPos(){
int l=1,r=n,mid;M1=Query(1,n);
while(l<r){
mid=(l+r)>>1;
if(Query(l,mid)==M1) r=mid;
else l=mid+1;
}
M=l;
}

string s;

inline void Work(){
Read(),GetPos();
for(REG int i=1;i<=k;++i)
for(REG int j=0;j<Subs[i].size();++j)
if(Subs[i][j]==M) S=i;
if(!S){putchar('!');for(REG int i=1;i<=k;++i) printf(" %d",M1);puts("");fflush(stdout);}
else{
int Ans;
putchar('?');
for(REG int i=0;i<Subs[S].size();++i) Vis[Subs[S][i]]=1;
printf(" %d",n-Subs[S].size());
for(REG int i=1;i<=n;++i)
if(!Vis[i]) printf(" %d",i);
puts("");
fflush(stdout);
scanf("%d",&Ans);
putchar('!');
for(REG int i=1;i<S;++i) printf(" %d",M1);
printf(" %d",Ans);
for(REG int i=S+1;i<=k;++i) printf(" %d",M1);
puts("");
fflush(stdout);
}
Init();
cin>>s;
}

int main(){
fflush(stdout);
scanf("%d",&T);
while(T--) Work();
}
#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×