P2085 最小函数值
题目描述
有n个函数,分别为F1,F2,…,Fn。定义Fi(x)=Aix^2+Bix+Ci (x∈N*)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。
输入输出格式
输入格式:
输入数据:第一行输入两个正整数n和m。以下n行每行三个正整数,其中第i行的三个数分别位Ai、Bi和Ci。Ai<=10,Bi<=100,Ci<=10 000。
输出格式:
输出数据:输出将这n个函数所有可以生成的函数值排序后的前m个元素。这m个数应该输出到一行,用空格隔开。
引用一篇题解的解释部分:
对于上述问题的优化方法,比较好的是用堆来做。思路是这样的:首先,我们可以在所有“箭头”指向1的时候,对所有箭头对应的函数值建立小根堆;然后,每次从堆顶取走那个数,并将其所对应的“箭头”指向下一个函数值,然后把这个新的函数值代替那个取走的函数值放在堆顶,并自顶向下维护堆(大家可以证明一下,一直这样操作下去,堆的性质恒成立)。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct T
{
int m,mi,i;//最小函数值,这个值对应的x,编号
}x[10005];
int A[10005],B[10005],C[10005];
int l=0;
void swaps(int a,int b)
{
int t;
t=x[a].m;
x[a].m=x[b].m;
x[b].m=t;
t=x[a].mi;
x[a].mi=x[b].mi;
x[b].mi=t;
t=x[a].i;
x[a].i=x[b].i;
x[b].i=t;
}
void put(T d)
{
int now,next;
x[++l]=d;
now=l;
while(now>1)
{
next=now>>1;
if(x[now].m>=x[next].m)
{
break;
}
swaps(now,next);
now=next;
}
}
T get()
{
int now,next;
T res=x[1];
x[1]=x[l--];
now=1;
while(2*now<=l)
{
next=now<<1;
if(next<l && x[next].m>x[next+1].m)
{
next++;
}
if(x[now].m<=x[next].m)
{
break;
}
swaps(now,next);
now=next;
}
return res;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
T k;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&A[i],&B[i],&C[i]);
k.i=i;//这里不能直接用x[i],不然会乱
k.m=A[i]+B[i]+C[i];
k.mi=1;
put(k);
}
for(int i=0;i<m;i++)
{
k=get();
printf("%d ",k.m);
k.mi++;
k.m=A[k.i]*k.mi*k.mi+B[k.i]*k.mi+C[k.i];
put(k);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define N 10005
using namespace std;
int A[N],B[N],C[N];
struct T
{
int m,mi,i;
};
bool operator < (T a,T b)
{
return a.m>b.m;
}
priority_queue<T> x;
int main(){
int n,m;
scanf("%d%d",&n,&m);
T t;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&A[i],&B[i],&C[i]);
t.m=A[i]+B[i]+C[i];
t.mi=1;
t.i=i;
x.push(t);
}
for(int i=0;i<m;i++)
{
t=x.top();
x.pop();
printf("%d ",t.m);
t.mi++;
t.m=A[t.i]*t.mi*t.mi+B[t.i]*t.mi+C[t.i];
x.push(t);
}
return 0;
}