题目链接:
https://ac.nowcoder.com/acm/contest/881/C
题意:
现给你一个n维空间中的点
a
=
(
a
1
,
a
2
,
⋅
⋅
⋅
,
a
n
)
a = (a_1, a_2,···, a_n)
a=(a1,a2,⋅⋅⋅,an),保证
a
i
a_i
ai为整数,现在求另外一个n维空间中的点
p
p
p,需要满足条件:
①
p
1
,
p
2
,
⋅
⋅
⋅
,
p
n
∈
R
p_1, p_2, ···, p_n ∈ R
p1,p2,⋅⋅⋅,pn∈R
②
p
1
,
p
2
,
⋅
⋅
⋅
,
p
n
≥
0
p_1, p_2, ···, p_n \geq 0
p1,p2,⋅⋅⋅,pn≥0
③
∑
i
=
1
n
p
i
=
1
\displaystyle\sum_{i = 1}^{n}p_i = 1
i=1∑npi=1
④使得
∑
i
=
1
n
(
a
i
m
−
p
i
)
2
\displaystyle\sum_{i = 1}^{n}(\frac{a_i}{m} - p_i)^2
i=1∑n(mai−pi)2最小
最后输出这个式子的最小值
题解:
题目就是在满足一定约束条件下目标函数的最小值,如果没有那个不等式条件那就简单多了,用拉格朗日乘数法就解决了,但是这里多了一个条件②那样的不等式条件,所以用到了拉格朗日乘子法。
首先需要构造一个拉格朗日函数
L
(
p
1
,
p
2
,
⋅
⋅
⋅
,
p
n
,
λ
)
=
∑
i
=
1
n
(
a
i
m
−
p
i
)
2
+
2
λ
(
∑
i
=
1
n
p
i
−
1
)
L(p_1, p_2, ···, p_n, \lambda) = \displaystyle\sum_{i = 1}^{n}(\frac{a_i}{m} - p_i)^2 + 2\lambda(\displaystyle\sum_{i = 1}^{n}p_i - 1)
L(p1,p2,⋅⋅⋅,pn,λ)=i=1∑n(mai−pi)2+2λ(i=1∑npi−1)
如果没有那个不等式条件,只需要对所有项求偏导等于0,即
L
p
1
=
2
(
a
1
m
−
p
1
)
(
−
1
)
+
2
λ
=
0
L_{p_1} = 2(\frac{a_1}{m} - p_1)(-1) + 2\lambda = 0
Lp1=2(ma1−p1)(−1)+2λ=0
L
p
2
=
2
(
a
2
m
−
p
2
)
(
−
1
)
+
2
λ
=
0
L_{p_2} = 2(\frac{a_2}{m} - p_2)(-1) + 2\lambda = 0
Lp2=2(ma2−p2)(−1)+2λ=0
⋅
⋅
⋅
···
⋅⋅⋅
L
p
n
=
2
(
a
n
m
−
p
n
)
(
−
1
)
+
2
λ
=
0
L_{p_n} = 2(\frac{a_n}{m} - p_n)(-1) + 2\lambda = 0
Lpn=2(man−pn)(−1)+2λ=0
L
λ
=
∑
i
=
1
n
p
i
−
1
=
0
L_{\lambda} = \displaystyle\sum_{i = 1}^{n}p_i - 1 = 0
Lλ=i=1∑npi−1=0
但是这里有
p
1
,
p
2
,
⋅
⋅
⋅
,
p
n
≥
0
p_1, p_2, ···, p_n \geq 0
p1,p2,⋅⋅⋅,pn≥0,需要一项项带进去检验
p
i
≥
0
p_i \geq 0
pi≥0,如果不满足就舍弃即
p
i
=
0
p_i = 0
pi=0(取0是因为
p
i
≥
0
p_i \geq 0
pi≥0)
先对数组
a
a
a从小到大排序
从上面的求偏导我们可以得到
p
i
=
a
i
m
−
λ
p_i = \frac{a_i}{m} - \lambda
pi=mai−λ,如果当前已检查过符合条件的
p
i
p_i
pi的个数为
k
k
k
那么此时
L
λ
=
∑
i
=
1
k
p
i
−
1
=
0
L_{\lambda} = \displaystyle\sum_{i = 1}^{k}p_i - 1 = 0
Lλ=i=1∑kpi−1=0 可以得到
λ
=
∑
i
=
1
k
(
a
i
)
−
m
m
k
\lambda = \frac{\displaystyle\sum_{i = 1}^{k}(a_i) - m}{mk}
λ=mki=1∑k(ai)−m,带入
p
k
+
1
=
a
k
+
1
m
−
λ
p_{k+1} = \frac{a_{k+1}}{m} - \lambda
pk+1=mak+1−λ
得到
m
k
p
k
+
1
=
k
a
k
+
1
−
∑
i
=
1
k
a
i
+
m
≥
0
mkp_{k+1} = ka_{k+1} - \displaystyle\sum_{i = 1}^{k}a_i + m \geq 0
mkpk+1=kak+1−i=1∑kai+m≥0,如果符合条件继续判断下一项,如果不行那就停止(因为先排过序,之后结果只会更小)
现在假设最后的项数为
k
k
k,则
p
k
+
1
,
p
k
+
2
,
⋅
⋅
⋅
,
p
n
p_{k+1}, p_{k+2}, ···, p_n
pk+1,pk+2,⋅⋅⋅,pn均为0
则
∑
i
=
1
n
(
a
i
m
−
p
i
)
2
\displaystyle\sum_{i = 1}^{n}(\frac{a_i}{m} - p_i)^2
i=1∑n(mai−pi)2
=
∑
i
=
1
k
(
a
i
m
−
p
i
)
2
+
∑
i
=
k
+
1
n
a
i
2
m
2
= \displaystyle\sum_{i = 1}^{k}(\frac{a_i}{m} - p_i)^2 + \displaystyle\sum_{i = k + 1}^{n}\frac{a_i^2}{m^2}
=i=1∑k(mai−pi)2+i=k+1∑nm2ai2
=
k
λ
2
+
∑
i
=
k
+
1
n
a
i
2
m
2
= k\lambda^2 + \frac{\displaystyle\sum_{i = k + 1}^{n} a_i^2}{m^2}
=kλ2+m2i=k+1∑nai2
=
(
∑
i
=
1
k
(
a
i
)
−
m
)
2
+
k
∑
i
=
k
+
1
n
a
i
2
m
2
k
=\frac{(\displaystyle\sum_{i = 1}^k (a_i) -m)^2 + k\displaystyle\sum_{i = k + 1}^n a_i^2}{m^2k}
=m2k(i=1∑k(ai)−m)2+ki=k+1∑nai2
最后上代码
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pi 3.1415926
#define mp(x, y) make_pair(x, y)
#define vi vector<int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> Pair;
const int MAX = 1e4 + 10;
const ll mod = 1e9 + 7;
ll n, m;
ll a[MAX], pre[MAX];
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
bool cmp(const ll &a, const ll &b) { return a > b; }
int main() {
#ifdef ACM_LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(0);
while (~scanf("%lld%lld", &n, &m)) {
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
sort(a + 1, a + 1 + n, cmp);
//求前缀和
pre[0] = -m;
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] + a[i];
//找满足的项数
ll k = n;
for (int i = 1; i < n; i++)
if (i * a[i + 1] < pre[i]) {
k = i;
break;
}
ll p = pre[k] * pre[k], q = m * m * k;
for (int i = k + 1; i <= n; i++)
p += k * a[i] * a[i];
ll gcdd = gcd(p, q);
p /= gcdd; q /= gcdd;
if (q == 1 || !p)printf("%lld\n", p);
else printf("%lld/%lld\n", p, q);
}
return 0;
}