• 【CFR#655】F Omkar ans Modes


    题目

    交互题

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

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

    (1 le n le 2 imes 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 o 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
    ",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;
    
  • 相关阅读:
    Python——GUI编程 控件及常用信号
    Python——PYQT:控件基本使用
    Android 自己定义圆圈进度并显示百分比例控件(纯代码实现)
    Parallel and Perpendicular
    策略模式(Strategy Pattern)
    Linux Framebuffer驱动剖析之中的一个—软件需求
    Java知识总结---整合SpringMVC+Mybatis+Spring(二)
    wav音频文件头解析
    【EasyUi DataGrid】批量删除
    Spark SQL Catalyst源代码分析之UDF
  • 原文地址:https://www.cnblogs.com/AUSTIN-tkys/p/13406067.html
Copyright © 2020-2023  润新知