题目大意:
题目链接:https://www.luogu.org/problemnew/show/P2085
有
n
n
n个函数,分别为
F
1
,
F
2
,
.
.
.
,
F
n
F1,F2,...,Fn
F1,F2,...,Fn。定义
F
i
(
x
)
=
A
i
×
x
2
+
B
i
×
x
+
C
i
(
x
∈
N
∗
)
Fi(x)=A_i\times x^2+B_i\times x+C_i(x∈N*)
Fi(x)=Ai×x2+Bi×x+Ci(x∈N∗)。给定这些
A
i
A_i
Ai、
B
i
B_i
Bi和
C
i
C_i
Ci,请求出所有函数的所有函数值中最小的
m
m
m个(如有重复的要输出多个)。
思路:
作为一道正常的题目,肯定是满足
0
≤
A
i
,
B
i
,
C
i
0\leq A_i,B_i,C_i
0≤Ai,Bi,Ci的。否则
x
x
x越大函数值就越小。
显然
F
i
(
x
)
≤
F
i
(
x
+
1
)
Fi(x)\leq Fi(x+1)
Fi(x)≤Fi(x+1)。所以最基本的思路就是维护
n
n
n个指针,每个指针指向
F
1
∼
F
n
F1\sim Fn
F1∼Fn函数的
x
x
x有多大。
每次选择
n
n
n个函数值里面最小的,并且将这格函数的下一个计算出来。
这样时间复杂度是
O
(
n
m
)
O(nm)
O(nm)的。
我们发现查找最小值这一部分是可以用堆来维护的。这样每次的时间复杂度就是
O
(
log
n
)
O(\log n)
O(logn),总的时间复杂度是
O
(
m
log
n
)
O(m\log n)
O(mlogn)
代码:
#include <queue>
#include <cstdio>
#define mp make_pair
using namespace std;
const int N=10010;
int n,m,a[N],b[N],c[N],cnt[N];
priority_queue<pair<int,int> > q;
int f(int x,int y)
{
return a[x]*y*y+b[x]*y+c[x];
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i],&b[i],&c[i]);
q.push(mp(-f(i,1),i));
cnt[i]=1;
}
while (m--)
{
int x=-q.top().first,y=q.top().second;
printf("%d ",x);
q.pop();
q.push(mp(-f(y,++cnt[y]),y));
}
return 0;
}