zoukankan      html  css  js  c++  java
  • CF1329E Dreamoon Loves AA

    有个长度为(n)个数轴,数轴上标记了(0,n)以及中间的(m)个整点。你现在要在再标恰好(k)个不同的整点,最小化相邻整点间最大值-相邻整点间最小值。

    (nle 10^{15},mle 4*10^5,kle n-m)


    稍微转化:相当于题目给了一堆数(b_i),要给这些数进行拆分,拆分(k)次。

    显然有:如果对(b_i)拆分多少次,一定是尽量均分。设(d_i)。要求(sum d_i=K=k+m+1),最小化(max lceilfrac{b_i}{d_i} ceil-min lfloor frac{b_i}{d_i} floor)

    假如已经决定了答案((L,R)),一个必要条件是:(sum lceilfrac{b_i}{R} ceille K le sum lfloor frac{b_i}{L} floor)

    于是可以二分得到(R)的下界(R_0)(L)的上界(L_0)。并且发现(L_0le R_0)

    再看另一个条件:(forall i,exist x,Lle lfloor frac{b_i}{x} floor le lceil frac{b_i}{x} ceille R)

    ((L_0,R_0))带入,得到了一些不满足限制的(i)。为了让这些(i)满足限制就需要把(L)缩小或(R)扩大。以(L)缩小为例,由(lceil frac{b_i}{x} ceille R)(lceil frac{b_i}{R} ceille x),于是(L)缩小成(lfloor frac{b_i}{lceil frac{b_i}{R} ceil} floor)(R)扩大同理。把这两个东西记作(l_i,r_i)

    问题变为:有个集合,集合中放着(L_0,R_0)。对这些(i),选择放(l_i)(r_i)进入集合中。要求搞完之后集合中的极差最小。

    贪心:先全部选(l_i),对(l_i)排序,每次把(l_i)换出来把(r_i)丢进去。

    时间(O(mlg m))


    using namespace std;
    #include <bits/stdc++.h>
    #define M 400005
    #define ll long long
    #define du(x,y) (((x)+(y)-1)/(y))
    ll n,k;
    int m;
    ll a[M],b[M];
    ll L0,R0;
    void init(){
    	L0=R0=-1;
    	ll l=1,r=n;
    	while (l<=r){
    		ll mid=l+r>>1,s=0;
    		for (int i=0;i<=m;++i)
    			s+=du(b[i],mid)-1;
    		if (s<=k)
    			r=(R0=mid)-1;
    		else
    			l=mid+1;
    	}
    	l=1,r=n;
    	while (l<=r){
    		ll mid=l+r>>1,s=0;
    		bool bz=1;
    		for (int i=0;i<=m && bz;++i){
    			if (b[i]/mid==0)
    				bz=0;
    			s+=b[i]/mid-1;
    		}
    		if (bz && s>=k)
    			l=(L0=mid)+1;
    		else
    			r=mid-1;
    	}
    //	assert(L0!=-1 && R0!=-1);
    }
    pair<ll,ll> p[M];
    multiset<ll> s;
    int main(){
    	freopen("in.txt","r",stdin);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%lld%d%lld",&n,&m,&k);
    		for (int i=1;i<=m;++i)
    			scanf("%lld",&a[i]);
    		a[m+1]=n;
    		for (int i=0;i<=m;++i)
    			b[i]=a[i+1]-a[i];
    		init();
    		ll ans;
    		assert(L0<=R0);
    		bool bz=1;
    		for (int i=0;i<=m;++i)
    			bz&=((b[i]+R0-1)/R0<=b[i]/L0);
    		if (bz)
    			ans=R0-L0;
    		else{
    			s.clear();
    			s.insert(L0),s.insert(R0);
    			int k=0;
    			for (int i=0;i<=m;++i)
    				if (du(b[i],R0)>b[i]/L0){
    					p[++k]={b[i]/du(b[i],R0),du(b[i],b[i]/L0)};
    					s.insert(p[k].first);
    				}
    			sort(p+1,p+k+1);
    			ans=*s.rbegin()-*s.begin();
    			for (int i=1;i<=k;++i){
    				s.erase(s.find(p[i].first));
    				s.insert(p[i].second);
    				ans=min(ans,*s.rbegin()-*s.begin());
    			}
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    .XamlReader.Load()解决给定编码中的字符无效与无法创建未知类型
    ie中jQuery无法解析xml文件的解决方案[转帖]
    关于BI
    关天response.setContentType()和application/json
    win7 exe程序icon消失
    关于spring的p标签(转)
    人生的阶段(转)
    Firefox高版本中alert样式问题
    IDM606注册
    Java 线程池
  • 原文地址:https://www.cnblogs.com/jz-597/p/14449824.html
Copyright © 2011-2022 走看看