好题

题意:给你n<=100000个数,每个数范围[0,1000],然后给你一个最大的代价T,每次最多合并k个数成为一个数,代价为k个数的总和。问最后合成1个数的总代价不大于T的最小k

题解:我们首先知道当k越大,总代价会越小,这样我们就找到了单调性,可以二分k看是否满足代价(又见最大值最小化问题)。然后我们贪心寻找固定k的最小代价,可以想到每次取前k个最小的值合并成一个,再放入数组中继续这个操作,直到最后变成一个数,这样我们可以直接使用优先队列模拟。

但是直接做会超时,所以我就YY了一个优化的方法。我们可以看到数字个数虽然很多,但是范围很小(数字很密集),所以我们可以首先使用数组记录每种值的个数,然后合并时使用一个指针无回溯向后寻找。这样很方便,因为每次k个数的和一定不小于最大的那个数(指针的位置),这时我们就可以把这个和放入后面的数组中,保证了指针无回溯。但是数字大了后会很低效,所以我们在这时再使用优先队列就好。

可我就这样一直wa,wa,wa。究其原因就是贪心错了。

给个数据:

5 18

1 2 3 4 5

答案是4,但是直接这样计算答案就不是4。。。

因此还有一个问题就是:每次合并k个数意味着减少(k-1)个数,最后变成1个数意味着总共减少(n-1)个数,而(n-1)%(k-1)不等于0时我们需要首先合并前(n-1)%(k-1)+1个最小的数,接着再合并k个数,这样就不会出现最后合并时少于k个数的情况了。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Mod=1e9+;
const int Max=;
int pos[Max],num[Max];
struct node
{
int val;
bool operator<(const node &c)const
{
return val>c.val;
}
};
priority_queue<node> pque;//小顶堆
ll Check(int sma,int mid,int n)//从sma开始到n每次最多合并mid个最小代价
{
ll sum=0ll;
node tem;
while(!pque.empty())
pque.pop();
memset(pos,,sizeof(pos));
for(int i=sma; i<n; ++i)//初始化
{
if(num[i]<(ll)Max)
pos[(int)num[i]]++;
else
{
tem.val=num[i];
pque.push(tem);
}
}
int j=,tmp,tmp2;
n=n-sma;//个数可能变小
while(n>)
{
tmp=mid;
tmp2=;
while(j<Max&&n>&&tmp>)//数组里有
{
if(pos[j]==)//只能在这儿才++
{
++j;
continue;
}
tmp2+=j;
pos[j]--;
n--;
tmp--;
}
while(!pque.empty()&&tmp>&&n>)
{
tmp2+=pque.top().val;
pque.pop();
tmp--;
n--;
}
sum+=tmp2;
if(tmp2>=Max)//数组里存不下
{
tem.val=tmp2;
pque.push(tem);
}
else//可以存在数组里(并且一定存在最后访问的位置及后面)
pos[tmp2]++;
n++;
}
return sum;
}
int Dic(int n,int sma,int big,int m)//最大值最小化问题
{
sort(num,num+n);
int tmp,tmp2,tmp3,mm=m;
while(sma<big)
{
int mid=((sma+big)>>);
tmp=;
m=mm;
if((n-)%(mid-))//**每次合并mid个后有余数,余下的首先合并更优**
{
tmp=(n-)%(mid-)+;
tmp2=;
for(int i=;i<tmp;++i)
{
tmp2+=num[i];
m-=num[i];
}
tmp--;
tmp3=num[tmp];
num[tmp]=tmp2;
}
if(Check(tmp,mid,n)>m)//满足单调性
sma=mid+;
else
big=mid;
if(tmp)//注意num数组要修改回来
num[tmp]=tmp3;
}
return big;
}
int main()
{
int t,n;
ll m;
scanf("%d",&t);
while(t--)
{
scanf("%d %I64d",&n,&m);
for(int i=; i<n; ++i)
scanf("%I64d",&num[i]);
if(n<=)
printf("0\n");
else if(n==)
printf("2\n");
else
printf("%d\n",Dic(n,,n,m));
}
return ;
}

HDU 5884 Sort(2016年青岛网络赛 G 二分+贪心+小优化)的更多相关文章

  1. HDU 5884 Sort -2016 ICPC 青岛赛区网络赛

    题目链接 #include <iostream> #include <math.h> #include <stdio.h> #include<algorith ...

  2. hdu 5881 Tea (2016 acm 青岛网络赛)

    原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5881 Tea Time Limit: 3000/1000 MS (Java/Others)    Me ...

  3. 2016 年青岛网络赛---Sort(k叉哈夫曼)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5884 Problem Description Recently, Bob has just learn ...

  4. 2016 年青岛网络赛---Family View(AC自动机)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5880 Problem Description Steam is a digital distribut ...

  5. 2016 年青岛网络赛---Tea

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5881 Problem Description Tea is good. Tea is life. Te ...

  6. HDU 6215 2017Brute Force Sorting 青岛网络赛 队列加链表模拟

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6215 题意:给你长度为n的数组,定义已经排列过的串为:相邻两项a[i],a[i+1],满足a[i]&l ...

  7. HDU 5875 Function (2016年大连网络赛 H 线段树+gcd)

    很简单的一个题的,结果后台数据有误,自己又太傻卡了3个小时... 题意:给你一串数a再给你一些区间(lef,rig),求出a[lef]%a[lef+1]...%a[rig] 题解:我们可以发现数字a对 ...

  8. HDU 4004 The Frog's Games(2011年大连网络赛 D 二分+贪心)

    其实这个题呢,大白书上面有经典解法  题意是青蛙要跳过长为L的河,河上有n块石头,青蛙最多只能跳m次且只能跳到石头或者对面.问你青蛙可以跳的最远距离的最小值是多大 典型的最大值最小化问题,解法就是贪心 ...

  9. 2018青岛网络赛G - Couleur 区间上的启发式合并

    题意:给出\(a[1...n]\),共\(n\)次操作,每次删除一个位置\(p_i\)(强制在线),此时区间会变为两个分离的区间,求每次操作的最大区间逆序对 首先要知道必要的工具,按权值建立的主席树可 ...

随机推荐

  1. A Secret(KMP)

    A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)Total ...

  2. 常见的.NET面试题(130)

    1. 简述 private. protected. public. internal 修饰符的访问权限. 答 . private : 私有成员, 在类的内部才可以访问. protected : 保护成 ...

  3. POJ 1789 Truck History【最小生成树简单应用】

    链接: http://poj.org/problem?id=1789 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...

  4. TFS二次开发-基线文件管理器(2)-TFS登录

    首先需要做一个TFS的登录. 以前的文章是使用的DomainProjectPicker 最新的VS里面使用的是TeamProjectPicker 首先可以在WinForm程序上写一个Button,然后 ...

  5. Nginx 启动、停止、平滑重启和平滑升级 graceful shutdown of worker processes

    Controlling nginx http://nginx.org/en/docs/control.html nginx can be controlled with signals. The pr ...

  6. es6数组的一些函数方法使用

    数组函数forEach().map().filter().find().every().some().reduce()等 数组函数(这里的回调函数中的index和arr都可以省略,回调函数后有参数是设 ...

  7. C++学习之旅get、getline的使用方法

    C++学习之旅get.getline的使用方法 面向行的输入:cin.getline(). 该函数读取整行.它使用通过回车键输入的换行符来确定输入结尾.要调用这样的方法,能够使用cin.getline ...

  8. 启动hive --service metastore &出现Missing Hive Execution Jar: /opt/apache-hive-1.2.0-bin//lib/hive-exec-*.jar

    原因:出现上述问题通常是运行hive 在bin/目录下的脚本所致. 解决办法:就是让HIVE_HOME变量指向hive-trunk/build/dist目录,将$HIVE_HOME/bin添加到PAT ...

  9. SourceTree的基本使用---团队开发/参与开源

    1.实践入门-团队开发 如果你看到第二部分关于“参与开源”的内容,而你的需求是团队开发,你会发现几个不方便的地方: 1.1.组长建项目,组员每次提交,都需要组长审查同意merge 如果你觉得麻烦,组长 ...

  10. asp.net IRequiresSessionState

    在一般处理程序中,使用context.Session对象,必须先继承IRequiresSessionState接口. System.Web.SessionState.IRequiresSessionS ...