10086

my first title

my first paragraph

服装(交互题)

内核

  1. 注意:需要 fflush(stdout)cout << endl 刷新输出缓冲区。
  2. 交互题的套路:分治、二分、增量法。

题意简述

给定序列长度 \(n \in [2,150]\),你可以在一次询问里得到某一些点的本质不同颜色个数,格式为 k a_1 a_2 a_3 ... a_k
让你确定序列每一个位置的颜色。询问次数要求 \(\le 3500\)

分析

这里使用了增量法和倍增。考虑我们已经确定了前 \(i-1\) 个位置。(询问 \([l,r]\) 的结果记为 \(ask[l][r]\)

  • \(ask[1][i] = ask[1][i-1] + 1\),则说明前 \(i-1\) 个中没有与 \(a_i\) 相同颜色的,记下颜色为 ++tot
  • 否则我们要找到与 \(a_i\) 相同的前一个位置,即找到最左边的一个 \(res\) 使得 \(ask[res][i] = ask[res][i-1] + 1\) 那么说明结果就是 \(res-1\)。那么并查集维护即可。

考试的时候没有方向,在乱搞。这里区间之间的关系与颜色的密切相关使我们使用了增量法,大大简化问题。

CODE

#include<bits/stdc++.h>
using namespace std;
const int N = 155;
int n,col[N];
int ask[N][N];
int qry(int l,int r){
	if(l == r)return 1;
	if(ask[l][r])return ask[l][r];
	printf("%d ",r-l+1);
	for(int i = l;i<=r;++i)printf("%d ",i);
	fflush(stdout);
	int res;
	scanf("%d",&res);
	return ask[l][r] = res;
}
int tot,fa[N];
int pre[N];
int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main(){
	scanf("%d",&n);
	for(int i = 1;i<=n;++i)fa[i] = i;
	col[1] = ++tot;
	for(int i = 2;i<=n;++i){
		if(qry(1,i) == qry(1,i-1) + 1){
			col[i] = ++tot;
		}else{
			int l = 1, r = i-1, res = i-1;
			while(l <= r){
				int mid = (l + r) >> 1;
				if(qry(mid,i) == qry(mid,i-1) + 1){
					r = mid - 1;
					res = mid-1;
				}else l = mid+1;
			}
			fa[i] = find(res);
		}
	}
	printf("0 ");
	for(int i = 1;i<=n;++i)printf("%d ",col[find(i)]);
	fflush(stdout);
	return 0;
}
posted @ 2024-09-11 16:41  Luzexxi  阅读(12)  评论(0编辑  收藏  举报