标签:pac cstring 函数 不包含 ack 题目 查看 force 区间
题意:通过查询构造出答案要求的密码,每次查询可以询问数组A中指定的集合的最大值,最多可以查询12次,我们要构造的密码序列,对于一个密码Pi, Pi为除了Si这个集合中索引对应的数组A中的数字的最大值,Si是k个互不独立的集合。
分析:题目中说Si是k个互不独立的集合,也就是最大值的下标最多出现在一个集合中,所以密码串P中最多一个数字是和最大值不同的,其它都是最大值,所以我们先询问整个数组中的最大值,然后二分查找这个最大值所在的下标,查找的时候,我们查找包含最大值的区间,每次查找的时候,查找前缀和包含最大值的区间,不包含的时候,查找区间的最大值就会小于我们所要的答案,具有单调性。然后我们再遍历一下每个密码对应的集合,查看是不是包含最大值,如果有的话,我们最多询问一次集合,就可以查出最大值。总共次数为1 + log(1000) + 1 = 12次。
对于这个查询的过程,我们可以单独写成一个函数query。对于每次的查询,它都会输出这个查询区间的最大值,等待我们输入。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int N = 1005;
vector<int> v[N];
int res[N];
//写成一个函数查询
int query(int x)
{
printf("? ");
//查询的集合大小
printf("%d ", x);
for (int i = 1; i <= x; ++i)
{
printf("%d ", i);
}
printf("\n");
fflush(stdout);
//读入查询的区间内的最大值,并返回
int res;
scanf("%d", &res);
return res;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
//数组a的大小,集合的数量
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= k; ++i)
{
v[i].clear();
int sz;//集合的大小
scanf("%d", &sz);
int u;
for (int j = 1; j <= sz; ++j)
{
scanf("%d", &u);
v[i].push_back(u);
}
}
//查询整个数组a的最大值
int mx = query(n);
//查询mx所在的下标
int l = 1, r = n;
int pos = 1;
while (l < r) {
int mid = l + r >> 1;
if (query(mid) == mx) {
r = mid;
}
else {
l = mid + 1;
}
}
pos = l;
//最多一个位置的数不是mx
for (int i = 1; i <= k; ++i)
{
bool flag = false;
map<int, int> mp;
for (int j = 0; j < v[i].size(); ++j)
{
if (v[i][j] == pos)
{
//不包含最大值
flag = true;
}
mp[v[i][j]] = 1;//这个位置是不行的
}
if (!flag)
{
res[i] = mx;
}
else
{
printf("? ");
printf("%d ", n - v[i].size());
for (int i = 1; i <= n; ++i)
{
if (mp[i]) continue;
printf("%d ", i);
}
printf("\n");
fflush(stdout);
int p = 0;
scanf("%d", &p);
res[i] = p;
}
}
printf("! ");
for (int i = 1; i <= k; ++i)
{
printf("%d ", res[i]);
}
printf("\n");
fflush(stdout);
char tmp[100];
scanf("%s", tmp);
}
return 0;
}
CodeForces 1363D. Guess The Maximums
标签:pac cstring 函数 不包含 ack 题目 查看 force 区间
原文地址:https://www.cnblogs.com/pixel-Teee/p/13034359.html