一道中文题,就不用翻译了。
大意是讲,一串数字,可以按照输入的先后顺序扔到一个固定大小的缓冲池子里,这个池子里的数输出顺序随意。然后计算——
SP=1*Pi1+2*Pi2+3*Pi3+...+N*PiN(其中i1, i2, ... iN是1, 2, 3, ... N的一个排列)
问在满足sp <= q的情况下,缓冲池最小可以是多少?
很水的一道题,然而还是花了我好久。
首先得出一个结论,将缓冲池里的数字按照从大到小的的顺序输出,可以得到当前缓冲池大小的最优解。那么就找一个可以在将数字扔到池子里的时候就排好序的数据结构就好了。我选的是优先队列。
然后二分+模拟就可以了,二分枚举每次缓冲池的大小。刚开始的范围是1——n。
在进行二分前先计算出大小为1和为n的情况下是否能够满足条件,如果为1可以就直接输出结果,如果为n也不行也直接输出结果。
就是这么水,但是因为我的二分写的不怎么样,所以浪费了好多时间,导致下一题已经来不及做了……
代码——
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
#define LL long long struct Node
{
int a; bool operator < (const Node& x) const
{
return x.a > a;
} }; int n;
LL q;
int s[];
priority_queue <Node> que; bool Max()
{
LL maxn = ;
for(int i = ; i < n; i++)
{
maxn += s[i]*(i+);
}
if(maxn <= q) return ;
return ;
} bool Min()
{
while(!que.empty()) que.pop();
LL minn = ;
for(int i = ; i < n; i++)
{
Node p;
p.a = s[i];
que.push(p);
}
for(int i = ; i < n; i++)
{
Node p = que.top();
que.pop();
minn += p.a*(i+);
}
if(minn > q) return ;
return ;
} void ErFen()
{
int l = ;
int r = n;
while(l <= r)
{
int lr = (l+r)/;
int sum = ;
LL ans = ;
int ii = ;
for(int i = ; i < n; i++)
{
if(sum == lr)
{
Node p = que.top();
ans += p.a*(++ii);
que.pop();
sum--;
}
Node p;
p.a = s[i];
que.push(p);
sum++;
}
while(!que.empty())
{
Node p = que.top();
ans += p.a*(++ii);
que.pop();
}
if(ans == q) {l = lr; r = lr-;}
else if(ans > q) l = lr+;
else r = lr-;
}
printf("%d\n", l);
} int main()
{
//freopen("test.in", "r", stdin);
while(~scanf("%d", &n))
{
cin >> q;
for(int i = ; i < n; i++) scanf("%d", &s[i]);
if(Max())
{
printf("1\n");
continue;
}
if(Min())
{
printf("-1\n");
continue;
}
ErFen();
}
}