码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForces 1363D. Guess The Maximums

时间:2020-06-02 23:00:17      阅读:89      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!