【题目链接】
【题目考点】
1. 堆
【解题思路】
输入要求中有:“以下n行每行三个正整数,其中第i行的三个数分别位
A
i
A_i
Ai、
B
i
B_i
Bi和
C
i
C_i
Ci。”,
因此,可知二次函数的二次项系数a,一次项系数b,常数项c都是正整数。
由于
a
>
0
a>0
a>0,因此二次函数开口向上,顶点位置横坐标为
−
b
2
a
-\frac{b}{2a}
−2ab,已知本题中a,b都为正整数,那么二次函数顶点横坐标在负半轴。那么在x>0的范围内,二次函数是增函数。已知
x
∈
N
∗
x\in N^*
x∈N∗,即x是正整数,因此所有的函数都是增函数。
对于该函数来说,x=1时函数值最小,x=2时函数值第二小。。。
也就是说,在取
F
(
1
)
F(1)
F(1)前,一定不会取到
F
(
2
)
F(2)
F(2)。我们可以先把所有函数x=1时的值加入到一个集合中,取出其中的最小值,然后让生成该值函数的自变量加1,把求出函数值放到这个集合中。为了能够高效取出最小值,我们使用堆这一数据结构。具体做法如下:
设Func类,包含属性:二次项系数a,一次项系数b,常数项c以及当前自变量x。将x代入函数
F
(
x
)
=
a
x
2
+
b
x
+
c
F(x)=ax^2+bx+c
F(x)=ax2+bx+c可以求出函数值,每个函数类对象都可以求出唯一的函数值。
设堆pq,堆中保存的是Func类对象,堆中的优先级定义为:Func类对象的函数值越小,优先级越高。
先将各函数生成Func类对象,每个对象的x都为1。
循环m次,每次循环取堆顶,获得各Func类对象中的最小函数值,输出该值。而后删除堆顶,让该Func类对象离开堆,接着让该对象的x加1,再把这个新的对象插入堆。
【题解代码】
写法1:使用priority_queue类
#include <bits/stdc++.h>
using namespace std;
struct Func//表示一个函数
{
int a, b, c, x;
Func(int _a, int _b, int _c):a(_a), b(_b), c(_c)
{
x = 1;
}
Func(){}
int getVal()//求函数值
{
return a*x*x+b*x+c;
}
};
struct Cmp
{
bool operator () (Func &a, Func &b)
{
return b.getVal() < a.getVal();//优先条件为:函数值更小的Func对象更优先
}
};
int main()
{
priority_queue<Func, vector<Func>, Cmp> pq;
int n, m, a, b, c;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
cin >> a >> b >> c;
pq.push(Func(a, b, c));
}
for(int i = 1; i <= m; ++i)
{
Func f = pq.top();//f表示一个函数
pq.pop();
cout << f.getVal() << ' ';
f.x++;//f的x值增加1
pq.push(f);
}
return 0;
}
写法2:手写堆
#include <bits/stdc++.h>
using namespace std;
#define N 10005
struct Func//表示一个函数
{
int a, b, c, x;
Func(int _a, int _b, int _c):a(_a), b(_b), c(_c)
{
x = 1;
}
Func(){}
int getVal()//求函数值
{
return a*x*x+b*x+c;
}
};
template<class T, class IsPriorClass>
class PriorityQueue//优先队列类
{
private:
T heap[N];
int n;
IsPriorClass isPrior;//仿函数对象:用于比较两元素的优先级
void shiftUp(int i)//第i结点上移
{
if(i == 1)//p是根结点
return;
if(isPrior(heap[i/2], heap[i]))
{
swap(heap[i], heap[i/2]);
shiftUp(i/2);
}
}
void shiftDown(int i)//第i结点下沉
{
if(i > n/2)//如果i是叶子结点
return;
int sel;//选择交换的结点位置
if(2*i+1 <= n && isPrior(heap[2*i],heap[2*i+1]))//有右孩子且右孩子值更大
sel = 2*i + 1;
else//没有右孩子或左孩子值更大
sel = 2*i;
if(isPrior(heap[i],heap[sel]))
{
swap(heap[sel], heap[i]);
shiftDown(sel);
}
}
public:
PriorityQueue()
{
n = 0;
}
void push(T val)//堆中插入元素
{
heap[++n] = val;
shiftUp(n);
}
void pop()//删除堆顶
{
swap(heap[1], heap[n]);
n--;
shiftDown(1);
}
T top()//获取堆顶
{
return heap[1];
}
bool empty()//判断堆为空
{
return n == 0;
}
int size()//获取堆中元素个数
{
return n;
}
};
struct Cmp
{
bool operator () (Func &a, Func &b)
{
return b.getVal() < a.getVal();//优先条件为:函数值更小的Func对象更优先
}
};
int main()
{
PriorityQueue<Func, Cmp> pq;
int n, m, a, b, c;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
cin >> a >> b >> c;
pq.push(Func(a, b, c));
}
for(int i = 1; i <= m; ++i)
{
Func f = pq.top();//f表示一个函数
pq.pop();
cout << f.getVal() << ' ';
f.x++;//f的x值增加1
pq.push(f);
}
return 0;
}