P8879 『STA - R1』Crossnews 题解

Inaba_Meguru

2023-01-23 00:16:31

Solution

## 题目简述 > - 给定长度为 $n$ 的数列 $a_i$,求**实数不降**数列 $b_i$ 最小化 > > $$ \sum_{i=1}^n b_i(b_i-a_i) $$ > > - $n\leq 10^6$。 ## 解题思路 挺妙的题目。 我们可以先化一下式子,变成 $$ \sum_{i=1}^n (b_i-\dfrac{a_i}{2})^2-\sum_{i=1}^n \dfrac{a_i^2}{4} $$ 右边显然是定值,我们只要左边尽可能小,假设 $A_i=\dfrac{a_i}{2}$。 我们先观察一下 $n=2$ 的情况,有两种情况: - $A_1<A_2$ 那么取 $b_i=A_i$ 即可。 - 否则应该取 $b_i=\dfrac{A_1+A_2}{2}$。 也许我们可以观察到这样的情况,其实每个 $b_i$ 最理想的取值是 $A_i$,但是为了要满足单调不减的性质取不到 $A_i$。这个时候就应该和他的邻居一个取值。那么这个时候他的邻居也会受到影响,原来是可以取到 $A_i$ 的因为邻居的偏袒不得不取一个其他值使得总和最小。 我们不难发现,当我们要一段**极长**连续区间 $b[l,r]$ 取一个相等的数 $x$ 的时候,这个时候必然有: $$ x=\dfrac{1}{r-l+1}\sum_{i=l}^r A_i $$ > **证明:** 不难发现原式相当于 $\sum(x-A_i)=(r-l+1) x^2-2(r-l+1) \overline A x+C$,这里 $C$ 为常数,不难发现当 $x$ 取 $\overline A$ 时最小。 那有没有可能这个求出 $x$ 不满足不降呢?实际上如果不满足,也就是说 $x$ 取极大极小值的时候原式更小,那么这个时候,他就会和邻居一个数值,不满足极长。 我们最后只需要求出来这个 $b$ 即可。 考虑单调栈维护,每个位置维护一个极长区间的长度、数值 $len,x$,每次先进入一个 $(1,A_i)$ 如果当前栈末尾不满足单调的性质就不断向前一位合并,直到单调或只有一个元素位置。 至此我们就完成了这道题。 ## 参考代码 ```cpp #include<iostream> #include<cstdio> using namespace std; const int MAXN=1e6+5; int n; double a[MAXN],ans; struct node{ int len;double val; node (int le=0,double va=0){len=le,val=va;} }st[MAXN];int cnt=0; node merge(node x,node y){ return node(x.len+y.len,(x.len*x.val+y.len*y.val)/(x.len+y.len)); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lf",&a[i]); a[i]/=2; } for(int i=1;i<=n;i++){ st[++cnt]=node(1,a[i]); while(cnt>1&&st[cnt].val<st[cnt-1].val) st[cnt-1]=merge(st[cnt],st[cnt-1]),--cnt; } int l=0; for(int i=1;i<=cnt;i++) while(st[i].len--){ ++l; ans+=(st[i].val*(st[i].val-2*a[l])); } printf("%.9f",ans); return 0; } ```