C-Euclidean Distance (牛客多校第一场)均值不等式或者 KTT(?)

题意很简单就是求这个

\sum (p_{i}-a_{i}/m)^2的最小值。

但不过有一些约束条件

p_{i}\geq 0 and \sum p_{i}=1

首先当时第一眼,直接均值不等式

\sqrt{\frac{\sum (p_{i}-a_{i}/m)^2}{n}}\geq \frac{\sum (p_{i}-a_{i}/m)}{n}

然后一会儿样例过了,然后WA了。

然后讲题解就看见一个拉格朗日乘子法。我虽然依稀会一点,但不过没有做过还有不等式约束的式子啊。。。。

然后看了一下拉格朗日乘子法和KTT没一个看懂,全是专业的数学用语,然后直接例题都看不懂,还写了几个小时。哎太菜了。

后来看了看那些大佬的代码,发现都差不多。

最后还是我队友想了一种方法,就是理解上面的式子的图像意义。

就是到ai/m这些点的距离的平方的最小值。然后对于为负数的点,相对应的pi取为零。

对为正数的ai/m用均值不等式。可以样例都过不了。

然后思考了很久,发现即使小于零也可以使用均值不等式。

如何判断呢。

首先,因为pi为大于零的数,ai为大于等于-m,小于等于m的数。

假设前i个能取等号。在加上第i+1个能取等号。

则必有这样的判断式

\frac{sum[i]}{m*i}-\frac{1}{i}\leq \frac{a[i+1]}{m}

 假设如果右边大于的时候也成立。

则有这样的式子\frac{sum[i]}{m*i}-\frac{1-p_{i+1}}{i}=\frac{a[i+1]}{m}-p_{i+1}

处理一下可以得到\frac{sum[i]}{m*i}-\frac{1}{i}-\frac{a[i+1]}{m}=p_{i+1}*(\frac{1}{i}-1)

可以得到pi+1时小于零的,与题意矛盾,故不满足

#include "bits/stdc++.h"

using namespace std;
const double eps = 1e-8;
#define lowbit(x) x&-x
#define pll pair<ll,ll>
#define pii pair<int,int>
#define fi first
#define se second
#define make_pair makp

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}

typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const int N = 100000 + 10;
const int M = 2048 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
ll n, m, a[N], sum[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cerr.tie(0);
    while (cin >> n >> m) {
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a + 1, a + n + 1, greater<>{});
        ll p, q, cnt = n;
        sum[0] = 0;
        for (int i = 1; i <= n; i++) {
            sum[i] = sum[i - 1] + a[i];
        }
        for (int i = 1; i < n; i++) {
            if (a[i + 1] * i < sum[i] - m) {
                cnt = i;
                break;
            }
        }
        q = cnt;
        p = (sum[cnt] - m) * (sum[cnt] - m);
        for (int i = cnt + 1; i <= n; i++) {
            p += a[i] * a[i] * q;
        }
        q *= m * m;
        ll d = __gcd(p, q);
        p /= d, q /= d;
        if (p == 0) cout << "0" << endl;
        else if (q == 1) cout << p << endl;
        else cout << p << "/" << q << endl;
    }
    return 0;
}
发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/96481504