zoukankan      html  css  js  c++  java
  • hdu_5884_Sort(二分+单调队列)

    题目链接:hdu_5884_Sort

    题意:

    有n个数,每个数有个值,现在你可以选择每次K个数合并,合并的消耗为这K个数的权值和,问在合并为只有1个数的时候,总消耗不超过T的情况下,最小的K是多少

    题解:

    首先要选满足条件的最小K,肯定会想到二分。

    然后是如何来写这个check函数的问题

    我们要贪心做到使消耗最小,首先我们将所有的数排序

    然后对于每次的check的mid都取最小的mid个数来合并,然后把新产生的数扔进优先队列,直到最后只剩一个数。

    不过这样的做法是n*(logn)2 ,常数写的小,带优化能卡过去,不过我反正卡不过去,然后就需要一个数据结构优化一个log

    那就是用单调队列,可以先看看这篇文章  合并果子

    然而这里有个小细节,不注意是过不去的:

    对于n个数,一共要合并n-1个数,才能最后剩一个数,然后对于每次的mid,每次会合并mid-1个数,如果(n-1)%(mid-1)!=0,那么我们得先取(n-1)%(mid-1)+1个数来合并,这样后面合并的时候才能刚合适,如果不取,读者可以自己模拟一下,会出错。

     1 #include<bits/stdc++.h>
     2 #define F(i,a,b) for(int i=a;i<=b;++i)
     3 using namespace std;
     4 typedef long long ll;
     5 
     6 const int N=1e5+7;
     7 int t,n,T,a[N];
     8 ll inf=1e18;
     9 queue<ll>Q1,Q2;
    10 
    11 bool check(int mid)
    12 {
    13     ll ans=0;
    14     while(!Q1.empty())Q1.pop();
    15     while(!Q2.empty())Q2.pop();
    16     F(i,1,n)Q1.push(a[i]);
    17     int num=(n-1)%(mid-1);
    18     if(num)
    19     {
    20         ll tp=0;
    21         F(i,1,num+1)tp+=Q1.front(),Q1.pop();
    22         ans+=tp;
    23         Q2.push(tp);
    24     }
    25     while(1)
    26     {
    27         ll tp=0;
    28         F(i,1,mid)
    29         {
    30             ll x=inf,y=inf;
    31             if(Q1.empty()&&Q2.empty())break;
    32             if(!Q1.empty())x=Q1.front();
    33             if(!Q2.empty())y=Q2.front();
    34             if(x<y)tp+=x,Q1.pop();
    35             else tp+=y,Q2.pop();
    36         }
    37         ans+=tp;
    38         if(ans>T)return 0;
    39         if(Q1.empty()&&Q2.empty())break;
    40         Q2.push(tp);
    41     }
    42     return ans<=T;
    43 }
    44 
    45 
    46 int main(){
    47     scanf("%d",&t);
    48     while(t--)
    49     {
    50         scanf("%d%d",&n,&T);
    51         F(i,1,n)scanf("%d",a+i);
    52         sort(a+1,a+1+n);
    53         int l=2,r=n,mid,ans;
    54         while(l<=r)mid=(l+r)>>1,check(mid)?r=mid-1,ans=mid:l=mid+1;
    55         printf("%d
    ",ans);
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    iphone 使用委托(delegate)在不同的窗口之间传递数据
    创建单键模式的类
    读入Plist文件中的信息
    C#读取Excel,取值为空的解决办法!
    ORACLE 常见的数据类型
    ArcGISServer 将内网地图服务映射修改外网可以访问的地图服务
    C#中获取当前路径的几种方法
    sql server2005登录出错问题(转载)
    (转载)服务器控件的生命周期
    ORACLE 中ROWNUM用法总结(转载)
  • 原文地址:https://www.cnblogs.com/bin-gege/p/5887144.html
Copyright © 2011-2022 走看看