首页 技术 正文
技术 2022年11月8日
0 收藏 558 点赞 2,065 浏览 2301 个字

题目描述:

         有n个函数,分别为F1,F2,…,Fn。定义Fi(x)=Ai*x^2+Bi*x+Ci (x∈N*)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。

   输入样例:

 3 10
4 5 3
3 4 5
1 7 1

   输出样例:

 9 12 12 19 25 29 31 44 45 54
题目分析:
(MLE,TLE做法)看到题目我们第一眼肯定想到的是将每个函数枚举m次,然后对这n*m个数进行排序,输出前m个。代码如下:
 #include<cstdio>
#include<algorithm>
#define MAXSIZE 100000000+20
#define MAXN 10000+20
int a[MAXN],b[MAXN],c[MAXN];
int num[MAXSIZE]; int main(){
int n,m,k=;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
num[k++]=a[i]*j*j+b[i]*j+c[i];
std::sort(num+,num+k);
for(int i=;i<=m;i++)
printf("%d ",num[i]);
return ;
}

     这样做的正确性是显而易见的:题目要求给出最小的M个数,这最小的M个数是由这N个函数生成的,最坏情况就是这M个数都由一个函数生成。那么即使这样,x的最大值也只是等于M,因为我们都知道:当二次函数y=ax2+bx+c(a>0)时,抛物线开口朝上,y随x增大而增大。所以当x1=i,x2=j(i,j∈N+,i<j)时y1<y2,所以我们对于同一个函数来说,x越小生成的数越小,这点在AC的算法中有很重要的作用。

   通过上面所说的,我们可以得知x最大值也只是等于M,也就是说我们的枚举区间就是1~m。我们需要对每个函数都枚举一遍,所以这一步的时间复杂度是O(n*m),最高是一亿,暂时还没超时,但是这是无序的,也就是说我们要将这n*m个数排序。

   假设我们用的是最快的快排,没被卡快排,那么这一步的时间复杂度就是O(n*m*log2(n*m));总体时间复杂度就是O(n*m*log2(n*m)),对于n=10000,m=10000,这个时间复杂度明显超时,况且我们还要花O(n*m)空间开销,这也是吃不消的。

 (AC做法)因为全部都算出来再排序输出必然超时,所以我们必须想办法减少算出来的值。在做出TLE且MLE的做法的时候,我们就证明了对于同一个函数而言,x越小生成的数越小,那我们不难画出下面这个表:

与x+1的关系 x的值 1 2 3 4 5 6 7 8
函数 < < < < < < < <
f1 < < < < < < < <
f2 < < < < < < < <
f3 < < < < < < < <
f4 < < < < < < < <
f5 < < < < < < < <
f6 < < < < < < < <
f7 < < < < < < < <
< < < < < < < <

 

假设xi=1,xj=1时fi<fj
则xi=1,xj=xj+1时fi<fj
则当只存在fi和fj时xi=1时fi为最小值
稍加思考,我们可以想到下面一种贪心算法:
  一开始先取每个函数中x=1时的值,输出这中间最小的,然后将最小的更新为x=2时的情况,再输出最小的......
  说到最小,就想到了用最小堆实现,代码如下:
 #include<cstdio>
#include<algorithm>
#define min(a,b) (((a)<(b))?(a):(b))
using std::swap;
struct h{
int data;
int place;
}heap[+];
bool operator < (const h &X,const h &Y){ //重载小于号
return X.data<Y.data;
}
int a[+],b[+],c[+];
int x[+];
int n;
void put(int i){
while(i*+<=n){
if(min(heap[i*],heap[i*+])<heap[i]){ //比较左儿子和右儿子
if(heap[i*]<heap[i*+]){
swap(heap[i*],heap[i]);
i*=;
}else{
swap(heap[i*+],heap[i]);
i*=;
i++;
}
}else
break;
}if(i*<=n&&heap[i*]<heap[i]){
swap(heap[i*],heap[i]);
i*=;
}
} int main(){
int m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
for(int i=;i<=n;i++){
x[i]=; //保存每个函数的x用到了几
heap[i].data=a[i]+b[i]+c[i]; //当x=1的情况
heap[i].place=i;
}
for(int i=n;i>=;i--){
put(i); //建堆
}
for(int i=;i<=m;i++){
printf("%d ",heap[].data);
int &k=heap[].place;
heap[].data=heap[].data+*a[k]*x[k]+a[k]+b[k]; //自己去算,不想讲,初二数学--完全平方式
x[heap[].place]++;
put();
}
return ;
}
时间复杂度O((n+m)log2n),最坏情况20000*log2(10000)≈280000不会超时
空间复杂度O(n)最坏10000,约0.04MB,离上限128MB很远。
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,088
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,565
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,413
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,186
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,822
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,905