题目
题目描述
给出
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] n≤m,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,m≤105,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(Δx→0) 。变化量,不就是 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Δx→0f′(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+bj−bi
将每一个 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+2aib1−bi 中的系数 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 的。有没有错误呢?我确实不知道。请大佬指正!