LOJ#2569. 「APIO2016」最大差分 分块+交互

比较有趣的交互题.    

subtask1:    

由于每次调用这个函数可以返回值域中的最大值和最小值,所以可以每次查询出两个元素.   

那么每次查到 $x,y$ 后就将查询区间缩小为 $[x+1,y-1]$,这样可以在规定操作次数内解决问题.   

subtask2:   

这个 subtask 比较困难.  

首先,我们发现答案的下界是 $B=\frac{Max-Min}{n-1}$,那么所有在 $B$ 长度内的两个数都不会产生贡献.  

考虑将 $[Min,Max]$ 的值域分成 $m$ 块,每块的长度为 $B$,那么有贡献的两个数一定是一个块的最大值和下一块的最小值.             

查询总代价为: $n+1+n-1+n \leqslant 3n$.                         

code:   

#include "gap.h"
#include <cstdio> 
#include <algorithm> 
#include <cstring>     
#include <vector> 
#define pb push_back
#define ll long long      
using namespace std;
const ll inf=1000000000000000002ll;
vector<ll>a; 
void MinMax(ll l,ll r,ll &x,ll &y) {  
	printf("? %lld %lld\n",l,r);    
	fflush(stdout);    
	scanf("%lld%lld",&x,&y);    
	fflush(stdin);  
}
ll sol1(int len) {  
	ll l=-inf,r=inf;  
	int tot=0;  
	while(l<=r) {                
		ll mi,ma;   
		MinMax(l,r,mi,ma);      
		if(mi>=0) a.pb(mi),++tot;  
		if(ma>mi) a.pb(ma),++tot; 
		l=mi+1,r=ma-1;     
		if(tot==len) break; 
	}
	sort(a.begin(),a.end());  
	ll ans=0;  
	for(int i=1;i<a.size();++i) { 	
		ans=max(ans,a[i]-a[i-1]);  
	}
	return ans;  
}   
ll sol2(int len) { 
	ll s,t,p;   
	MinMax(0,inf,s,t);   
	p=(t-s)/(len-1);      
	ll ans=p;  
	ll pre=s;  
	for(ll i=s+1;i<=t;i+=p+1) {  
		ll a,b;  
		MinMax(i,i+p,a,b);   
		if(a!=-1) ans=max(ans,a-pre),pre=b;    
	}   
	return ans; 
}
long long findGap(int T, int N)
{
	if(T==1) return sol1(N);  
	else { 
		return sol2(N); 
	}    
}
int main() { 
	int T,n;  	
	scanf("%d%d",&T,&n);   
	fflush(stdin);  
	printf("! %lld\n",findGap(T,n)); 
	return 0; 
}

  

 

posted @ 2020-08-04 09:38  EM-LGH  阅读(140)  评论(0编辑  收藏  举报