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

【CFR#655】F Omkar ans Modes

时间:2020-07-30 22:16:14      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:mat   bit   query   ==   scan   数字   make   pre   最小   

题目

交互题

给出长度为\(n\)的单调不减序列,一次询问可以询问\([l,r]\)中的众数\(x\)(如果多个数字出现次数相同则返回最小的数字)以及\(x\)出现的次数\(f\)

\(n\)中不同数字的个数为\(k\),询问次数不得超过\(4k\) ,输出整个的序列

\(1 \le n \le 2\times 10^5 \ , \ 1 \le k \le 25000\)

题解

调用函数\(solve(1,n)\)

  • \(query(1,n)\)得到$(x,f) $(1)
  • 找到满足\(2^k \le f \lt 2^{k+1}\)\(k\) ,query查询\(1 \to n\)中下标为\(2^k\)的倍数的点(2)
  • 查询值为\(x\)的可能有\(1\)\(2\)(3)
    • 如果只有一个位置值为\(x\),设为\(j\),那么\([j,j+2^k-1]\)\([j-2^k+1,j]\) 中至少有一个众数为\(x\),同时询问这两个区间即可得到\(x\)的准确位置
    • 如果有两个位置的值为\(x\),设为\(j_1\)\(j_2\),那么\([j_1-2^k+1,j_2]\)\([j_1,j_2+2^k-1]\) 的众数均为\(x\),询问任意一个区间即可得到\(x\)的准确位置
  • 递归调用solve确定左右两边剩下的区间

复杂度分析

  • \(solve\)会被准确地调用\(k\)次,因此(1)的复杂度为\(O(k)\)
  • 如果每次将(2)的查询存储起来,对于一个数值,一定被query一次或者两次,并且query一次的在(3)中被query两次,query两次的在(3)中被query一次,那么(2)(3)的复杂度为\(O(3k)\)
  • 故总的询问复杂度为\(O(4k)\),时间复杂度应为\(O(n log \ n)\)
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk make_pair 
using namespace std;
const int N=400010;
int n,a[N],x,f,k,p1,p2;
pii query(int l,int r){
	printf("? %d %d\n",l,r);
	fflush(stdout);
	scanf("%d %d",&x,&f);
	return mk(x,f);
}
void solve(int l,int r){
	pii q=query(l,r);
	if(q.second==r-l+1){
		for(int i=l;i<=r;++i)a[i]=q.first;
		return ;
	}
	for(k=1;(k<<1)<=q.second;k<<=1);
	int i=k,L,R;while(i<l)i+=k;
	for(;i<=r;i+=k){
		if(!a[i])a[i]=query(i,i).first;
		if(a[i]==q.first){p1=i;break;}
	}
	p2=p1+k;
	if(p2<=r&&!a[p2])a[p2]=query(p2,p2).first;
	if(a[p1]==a[p2]){
		pii p=query(max(l,p1-k+1),p2);
		L=p2-p.second+1,R=p2+q.second-p.second;
	}else {
	//	k>>=1;
		pii p=query(max(l,p1-k+1),p1);
		if(p.first==q.first)
			L=p1-p.second+1,R=p1+q.second-p.second;
		else {
			p=query(p1,min(p1+k,r));
			R=p1+p.second-1,L=p1-q.second+p.second;
		}
	}
	for(int j=L;j<=R;++j)a[j]=q.first;
	if(l<L)solve(l,L-1);
	if(R<r)solve(R+1,r);
}
int main(){
//	freopen("F.in","r",stdin);
//	freopen("F.out","w",stdout);
	scanf("%d",&n);
	solve(1,n);
	printf("! ");for(int i=1;i<=n;++i)printf("%d ",a[i]);
	fflush(stdout);
	return 0;
}//tkys_Austin;

【CFR#655】F Omkar ans Modes

标签:mat   bit   query   ==   scan   数字   make   pre   最小   

原文地址:https://www.cnblogs.com/AUSTIN-tkys/p/13406067.html

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