您的位置:首页 > 其它

2016 ACM/ICPC Asia Regional Qingdao Online hdu 5884 Sort (二分+优先队列)★

2016-09-17 18:54 337 查看
题意:

给定n个序列,以及他们的长度,问在总花费不超过T,每次合并的序列个数不多于k的情况下,k的最小值,合并的代价是合并序列的总长度和。

题解:

二分k,再用优先队列取出前k个小的,模拟下去,不过这样会T。由于ai小于1000,所以可以记录这1000个数出现的次数,将出现的数字压入队列,每次出队的时候判断一下就不T了。不过还有一个问题,比如长度为6的序列,每次取前3个,最后一次只会取最后两个,那么我们显然在一开始取两个会使代价更小。

这里的处理就是在一开始合并k1个,结果赛场敲渣了。。。。然后意淫出在队首补0,使得最后一次仍然取k个,强行A掉。。。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
#include <bitset>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF  0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-3
#define maxn 100100
#define MOD 1000000007

struct cmp
{
bool operator ()(int &a,int &b)
{
return a > b;
}
};
int n;
long long m;
int Num[1010];
int num[1010];
int solve(int x)
{
int cnt = n;
while(cnt >= x)
cnt -= x-1;
return x - cnt;
}
int main()
{
int t,C = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d%lld",&n,&m);
memset(Num,0,sizeof(Num));
for(int i = 0; i < n; i++)
{
int x;
scanf("%d",&x);
Num[x]++;
}
int l = 1,r = n;
while(r - l > 1)
{
int mid = (l+r) / 2;
priority_queue<int,vector<int>,cmp> q;
memcpy(num,Num,sizeof(Num));
for(int i = 0; i < 1010; i++)
if(num[i])
q.push(i);
if(solve(mid) != mid - 1)
{
if(!num[0])
q.push(0);
num[0] += solve(mid);
}
long long ssum = 0;
while(!q.empty())
{
int cnt = 0;
long long sum = 0;
while(cnt < mid && !q.empty())
{
if(q.top() > 1000)
{
sum += q.top();
q.pop();
cnt++;
}
else
{
int l = min(num[q.top()],mid-cnt);
sum += q.top() * l;
num[q.top()] -= l;
if(!num[q.top()])
q.pop();
cnt += l;
}
}
if(cnt <= 1)
break;
if(sum <= 1000)
{
if(!num[sum])
q.push(sum);
num[sum]++;
}
else
q.push(sum);
ssum += sum;
if(ssum > m)
break;
}
if(ssum <= m)
r = mid;
else
l = mid;
}
printf("%d\n",r);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: