Codeforces Round #618 (Div. 2) E

Problem

Codeforces 题目地址

Solution

看完qsc大佬的题解后才发现真的是考场降智啊!!!是真的蠢啊!!!

假设前 \(k-1\) 个数已经通过调整达到了最小字典序,调整成了 \(m\) 块,第 \(i\) 的数(因为都是一样的就叫一块)是 \(x_i\)。很显然满足一个条件:\(x_1 < x_2 < ... < x_m\)

现在加入第 \(k\) 个数

\(k\) 个数的左边是 \(x_m\) 这一块,我们只要比较一下 \(a_k\)\(x_m\) 的大小。如果 \(a_k < x_m\),说明把 \(a_k\) 加入到 \(x_m\) 可以更优(平均数更小),这时 \(x_m\) 发生了改变,我们要继续类似地比较 \(x_m\)\(x_{m-1}\),直到满足条件。如果 \(a_k > x_m\)\(a_k\) 又可以作为单独的一块加入到后面,变成 \(x_{m+1}\)

昨晚还瞎想用啥数据结构,实际上完全不需要。。。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 1e6+7;
int n,tot;
int L[N];
double a[N],b[N];
int main()
{
    n = read();
    for(int i=1;i<=n;++i)
        a[i] = read();
    for(int i=1;i<=n;++i) {
        b[++tot] = a[i]; L[tot] = 1;
        while(tot>=1 && b[tot]<b[tot-1]) {
            b[tot-1] = (L[tot-1]*b[tot-1]+L[tot]*b[tot]) / (L[tot-1] + L[tot]);
            L[tot-1] += L[tot];
            --tot;
        }
    }
    for(int i=1;i<=tot;++i)
        for(int j=1;j<=L[i];++j)
            printf("%.9lf\n",b[i]);
    return 0;
}

Summary

这题的这种解法灵活地避开了数据结构这个死胡同,其核心思想是数学归纳法 + 贪心

这启发我们遇到类型的问题可以先不管全局,考虑如果前面已经符合条件,第 \(k\) 个应该怎么处理?

结合题目是最优化问题,考虑合适的贪心。

猜你喜欢

转载自www.cnblogs.com/BaseAI/p/12291569.html