zoukankan      html  css  js  c++  java
  • CF R 639 div2 F Review 贪心 二分

    LINK:Résumé Review

    这道题让我眼前一亮没想到二分这么绝.

    由于每个(b_i)都是局部的 全局只有一个限制(sum_{i=1}^nb_i=k)

    所以dp没有什么用 我们只需要满足他们的累和=k即可。

    容易想到每次给b加1带来的贡献是 (Delta_x=a_i-3{b_i}^2-3b_i-1)

    开一个堆每次取出最大值 这样显然是最优的。

    不过复杂度为klogn k足足有1e14这么大。

    一个绝妙的想法 每次增加的值是递减的 那么第k次增加的值也是固定的。

    可以进行二分第k次增加的值 此时我们可以快速算出之前的所有的(b_i) 至此从而判定答案是否是最优的。

    正确性比较显然 值得一提的是 二分出来之后 我的处理办法是 让每个b都达到临界点 即再增加1就会<=当前mid

    这样的话 对于二分出小于答案的那些都会不合法 最后唯一被卡在最左边界的就是答案了。

    值得一提的是 求出每个b 可以直接解方程 也可以采用二分 不过解方程之后调整次数我难以把握 所以再接了一个二分.

    不过前者复杂度可以认为是nlogn 后者则是nlog^2.

    /一个显然的做法 开堆贪心 klogn
    //在这个过程中可以发现每次增加的值递减 可以二分出来这个东西.
    const ll MAXN=100010;
    ll n,k,ww;
    ll a[MAXN],b[MAXN];
    inline ll f(ll a,ll b){return a==b?-INF:a-3*b*(b+1)-1;}
    //二分出来的东西要尽可能的<=x
    inline ll calc(ll a,ll x)//询问当递减的值为x时的bi的值.
    {
    	ll l=0,r=a;
    	while(l+1<r)
    	{
    		ll mid=(l+r)>>1;
    		if(f(a,mid)>x)l=mid;
    		else r=mid;
    	}
    	if(f(a,r)>x)return min(r+1,a);
    	return r;
    }
    inline ll check(ll x)//递减的值为x.
    {
    	ww=0;
    	rep(1,n,i)
    	{
    		b[i]=calc(a[i],x);
    		ww+=b[i];
    	}
    	return ww<k;
    }
    signed main()
    {
    	freopen("1.in","r",stdin);
    	ll l=0,r=0;
    	get(n);get(k);
    	rep(1,n,i)get(a[i]),r=max(r,f(a[i],0)),l=min(l,f(a[i],a[i]-1));
    	while(l+1<r)
    	{
    		ll mid=(l+r)>>1;
    		if(check(mid))r=mid;
    		else l=mid;
    	}
    	if(check(l))r=l;
    	check(r);k-=ww;
    	rep(1,n,i)if(k>0&&b[i]<a[i]&&f(a[i],b[i])==r)++b[i],--k;
    	rep(1,n,i)put_(b[i]);return 0;
    }
    
  • 相关阅读:
    0039. Combination Sum (M)
    imei和imsi
    APP网络测试要点和弱网模拟
    Git常用命令
    HTTP host头
    与apk签名有关的那些概念与命令
    你应该知道的运维术语
    nginx、fastCGI、php-fpm关系梳理
    adb连接手机报错解决方案汇总(win7)
    Android DVM
  • 原文地址:https://www.cnblogs.com/chdy/p/12849265.html
Copyright © 2011-2022 走看看