理解:假设n=7,k=3,A=[1 5 3 7 2 6 4],按照题意将A划分为3个集合,s1=[1,4],s2=[2,5],s3=[3,6,7]。其中s1,s2,s3是所划分集合中元素的下标,对应的w1=[A[1]=1,A[4]=7],w2=[5,2],w3=[3,6,4]。
求解:答案总共有为k个数字,从p1到pk,对于每个pi,当前的值是A[]中删去当前集合中所有下标所对应的值后的全局最大值。这里可以发现,如果A[]最大值MX不在当前的划分,那么当前的pi就是MX,否则就要模拟一次求解。所有,用1次查询找到MX,用<=10次的查询找到MX的下标,对于仅有的当前划分包含MX的,再用1次查询,可在<=12查询中求得正确解。
int t;
vector<int> G[1005];
int query(int x)
{
int ans;
printf("? %d ", x);
f(i, 1, x)printf("%d ", i);
cout << endl;
scanf("%d", &ans);
return ans;
}
void wo()
{
vector<int> res;
f(i, 1, 1004)G[i].clear();
int n, k, x, y;
scanf("%d%d", &n, &k);
f(i, 1, k) {
scanf("%d", &x);
f(j, 1, x)
scanf("%d", &y), G[i].emplace_back(y);
}
int mx = query(n);//1次
//二分查询区间最大值,找到最大值所在集合
int l = 1, r = n;
int idx=-1;
while (l <= r)//2^10=10次
{
int mid = (l + r) / 2;
if (query(mid) == mx)
{
idx = mid;
r = mid - 1;
}
else l = mid + 1;
}
f(i, 1, k)
{
bool fg = false;
for (auto I : G[i])
{
if (I == idx) { fg = true;break; }
}
if (fg) //最大值在当前集合,再找一次
{
int tmp;
set<int> st;
f(j, 1, n)st.insert(j);
for (auto I : G[i])st.erase(I);
printf("? %d ",st.size());
for (auto I : st)printf("%d ", I);
cout << endl;
scanf("%d", &tmp);
res.emplace_back(tmp);
}
else res.emplace_back(mx);
}
printf("! ");
for (auto I : res)printf("%d ", I);
cout << endl;
}
int main()
{
cin >> t;
while (t--)
{
wo();
string op;
cin >> op;
if (op == "Correct")continue;
else break;
}
return 0;
}