函数

137 篇文章 1 订阅
89 篇文章 0 订阅

题目

题目描述
给出 n n n 个二次函数 f i ( x ) = a i x 2 + b i x + c i ( i ∈ [ 1 , n ] ) f_i(x)=a_ix^2+b_ix+c_i(i\in[1,n]) fi(x)=aix2+bix+ci(i[1,n]) 。求一组正整数 x i ( i ∈ [ 1 , n ] ) x_i(i\in[1,n]) xi(i[1,n]) ,满足 ∑ i = 1 n x i = m \sum_{i=1}^{n}x_i=m i=1nxi=m ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi) 最小。

输出 ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi) 即可。

输入格式
第一行是两个正整数 n , m n,m n,m ;接下来 n n n 行,第 i + 1 i+1 i+1 行是三个整数 a i , b i , c i a_i,b_i,c_i ai,bi,ci(含义见题面)。

输出格式
共一行,一个整数,表示 ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi)

数据范围与约定

数据点编号 m m m
1 , 2 1,2 1,2 ≤ 10 \le10 10
3 , 4 3,4 3,4 ≤ 100 \le 100 100
5 , 6 5,6 5,6 ≤ 500 \le 500 500
7 , 8 , 9 , 10 7,8,9,10 7,8,9,10 ≤ 5000 \le 5000 5000
∀ x ∈ [ 11 , 20 ] \forall x\in[11,20] x[11,20] ≤ 1 0 5 \le10^5 105

对于所有数据满足:

  • n ≤ m , a i ∈ [ 1 , 1 0 3 ] n\le m,a_i\in[1,10^3] nm,ai[1,103]
  • b i , c i ∈ [ − 1 0 3 , 1 0 3 ] b_i,c_i\in[-10^3,10^3] bi,ci[103,103]

思路

暴力。考虑每次将某个 x x x 增大 1 1 1 。直接用堆即可。时间复杂度 O ( m log ⁡ n ) \mathcal O(m\log n) O(mlogn)


2019 / 12 / 1    u p d a t e {\tt 2019/12/1\; update} 2019/12/1update

原来我根本没有意识到正确性是由 a > 0 a>0 a>0 保证的……

一个 a > 0 a>0 a>0 的二次函数,开口向上,令 g ( x ) = f ( x + 1 ) − f ( x ) g(x)=f(x+1)-f(x) g(x)=f(x+1)f(x) ,一定有 g ( x ) g(x) g(x) 单增。从导数的角度很好说明。

所以,如果你不将 g ( x ) g(x) g(x) 最小的 x i x_i xi 增加,其余的 g ( x ) g(x) g(x) 一定恒大于该 g ( x ) g(x) g(x),一定不优。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
inline int readint(){
	int a = 0, f = 1; char c = getchar();
	for(; c<'0' or c>'9'; c=getchar())
		if(c == '-') f = -1;
	for(; '0'<=c and c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(long long x){
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) writeint(x/10);
	putchar(x%10+'0');
}

const int MaxN = 100000;
int n, m, a[MaxN], b[MaxN], c[MaxN];
inline long long function(int i,long long x){
	return a[i]*x*x+b[i]*x+c[i];
}
inline long long addv(int i,long long x){
	return function(i,x+1)-function(i,x);
}
struct Status{
	int id, x;
	Status(int I,int X):id(I),x(X){ }
	bool operator<(const Status &that)const{
		return addv(id,x) > addv(that.id,that.x);
	}
};
priority_queue<Status> pq;

int main(){
	n = readint(), m = readint();
	for(int i=0; i<n; ++i){
		a[i] = readint();
		b[i] = readint();
		c[i] = readint();
	}
	long long ans = 0;
	for(int i=0; i<n; ++i){
		ans += function(i,1);
		pq.push(Status(i,1));
	}
	for(int i=n; i<m; ++i){
		auto p = pq.top(); pq.pop();
		ans += addv(p.id,p.x ++);
		pq.push(p);
	}
	writeint(ans), putchar('\n');
	return 0;
}

延伸题目

题目描述
n n n个二次函数 f i = a i x 2 + b i x + c i ( i ∈ [ 1 , n ] ) f_i=a_ix^2+b_ix+c_i(i\in[1,n]) fi=aix2+bix+ci(i[1,n]),求一组 实数 x i ( i ∈ [ 1 , n ] ) x_i(i\in[1,n]) xi(i[1,n]),满足 ∑ i = 1 n x i = m \sum_{i=1}^{n}x_i=m i=1nxi=m ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi) 最小。

输出 ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi) 即可。

输入格式
第一行,一个正整数 n n n 和一个 非负实数 m m m;接下来 n n n 行,第 i + 1 i+1 i+1 行是三个 实数 a i , b i , c i a_i,b_i,c_i ai,bi,ci(含义见题面)。

输出格式
共一行,一个 实数 ,表示 ∑ i = 1 n f i ( x i ) \sum_{i=1}^{n}f_i(x_i) i=1nfi(xi) 。保留两位小数。

数据范围与约定
对于所有数据都有:

  • n , m ≤ 1 0 5 , a i ∈ ( 0 , 1 0 3 ] n,m\le 10^5,a_i\in(0,10^3] n,m105,ai(0,103]
  • b i , c i ∈ [ − 1 0 3 , 1 0 3 ] b_i,c_i\in[-10^3,10^3] bi,ci[103,103]

思路

推广到实数域之后,使用堆来存储的方法就不适用了。

现在该怎么办呢?——虽然存不下,我们还是应该考虑一下原来的方法。

考虑每次将一个 x x x 变大 Δ x ( Δ x → 0 ) \Delta x(\Delta x\rightarrow 0) Δx(Δx0) 。变化量,不就是 f ′ ( x ) Δ x f'(x)\Delta x f(x)Δx 吗?而且,因为 lim ⁡ Δ x → 0 f ′ ( x − Δ x ) = f ′ ( x ) \lim_{\Delta x\rightarrow 0}f'(x-\Delta x)=f'(x) limΔx0f(xΔx)=f(x) ,所以无论增大、减小,变化量都是 f ′ ( x ) Δ x f'(x)\Delta x f(x)Δx

所以,最优情况下, f ′ ( x ) f'(x) f(x) 应该全部相等。否则,将 f ′ ( x ) f'(x) f(x) 较小的 x x x 增加 Δ x \Delta x Δx 、较大的减少 Δ x \Delta x Δx ,就会得到更优的解。

解方程 f i ′ ( x i ) = f j ′ ( x j ) f'_i(x_i)=f'_j(x_j) fi(xi)=fj(xj) ,即 2 a i x i + b i = 2 a j x j + b j 2a_ix_i+b_i=2a_jx_j+b_j 2aixi+bi=2ajxj+bj,得到

x i = 2 a j x j + b j − b i 2 a i x_i=\frac{2a_jx_j+b_j-b_i}{2a_i} xi=2ai2ajxj+bjbi

将每一个 x i ( i ≠ 1 ) x_i(i\ne 1) xi(i=1) x 1 x_1 x1 建立关系(即,用带 x 1 x_1 x1 的式子表示 x i x_i xi ),就可以通过 ∑ i = 1 n x i = m \sum_{i=1}^{n}x_i=m i=1nxi=m 解出 x 1 x_1 x1 。然后一一还原即可!


2019 / 12 / 1    u p d a t e {\tt 2019/12/1\; update} 2019/12/1update

会不会无解呢?数据保证了 a > 0 a>0 a>0,所以 x i = a 1 a i x 1 + b 1 − b i 2 a i x_i=\frac{a_1}{a_i}x_1+\frac{b_1-b_i}{2a_i} xi=aia1x1+2aib1bi 中的系数 a 1 a i \frac{a_1}{a_i} aia1为正,所以总和也为正,故一定有解。而且 a > 0 a>0 a>0 也可以保证答案不会变成 − ∞ -\infty .


时间复杂度 O ( n ) \mathcal O(n) O(n)竟然比整数域的情况还要快

代码

然而并没有代码,因为根本没有这道题,这是我自己口胡的。所以题解也是我自己 y y yy yy 的。有没有错误呢?我确实不知道。请大佬指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值