[luogu]P2085最小函数值-堆排的玄学运用

4 篇文章 0 订阅

题目描述

有n个函数,分别为F1,F2,...,Fn。定义Fi(x)=Ai*x^2+Bi*x+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: 
3 10
4 5 3
3 4 5
1 7 1
输出样例#1: 
9 12 12 19 25 29 31 44 45 54






说明

数据规模:n,m<=10000


//那么来说一下这道题的玄学思路,原先我就是简单的做了一个n套m的循环然后堆排,结果只过了两个点其余全都tle。但若要计算每一个函数的可能值必定要n*m,顿觉无解

//但是,那么问题来了(敲黑板),我们并不一定枚举每个函数的值,我把每个函数都求了下x=1时的值,然后用结构体存下函数组数与函数x=1时的值。处理排序时,先找出x=1时函数值最小的值(普通sort)并命名为syq是dalao函数,把其余函数命名为zfh是蒟蒻函数。然后给x值++并带入syq是dalao函数,放入堆中并对比其余zfh是蒟蒻函数x=1时的值,堆排,最后速度会很快,大概只有60ms左右,内存也只有2mb,而原来的方案却是12000ms与300mb的时复与空复,所以解法的确很烧脑很玄学

//上代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;


int n,m,a[maxn],b[maxn],c[maxn];
int f[maxn];//f会一直++,带入x=1时最小的函数 
struct EA{
    int data;
    int nm;
}x[maxn];

int cmp(EA f1,EA f2){
    return f1.data<f2.data;
}


int main(){
    for(int i=1;i<=10000;i++)
    	f[i]=2;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i]>>c[i];
        x[i].data=a[i]+b[i]+c[i];
        x[i].nm=i;//组数 
	}
	
    sort(x+1,x+n+1,cmp);
    for(int i=1;i<=m;i++){
        cout<<x[1].data<<" ";//找到x=1时最小的函数,命名为syq是dalao函数,其余函数都命名为zfh是蒟蒻函数 
        int g=x[1].nm;//g是函数组数 
        x[1].data=f[g]*a[g]*f[g]+b[g]*f[g]+c[g];//f一直++并带入syq是dalao函数 
        f[g]++;
        int t=1;
        while(t*2<=n){//看余下zfh是蒟蒻函数在x=1时其中有无带入比当前syq是dalao函数的值还小 
            int tp=t*2;
            if(tp+1<=n&&(x[tp+1].data<x[tp].data)) tp++;//堆排 
            if(x[tp].data<x[t].data){
                EA kx=x[tp];//有就交换 
                x[tp]=x[t];
                x[t]=kx;
                t=tp;
            }//if
            else break;
        }//while
    }//for
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值