P4072 [SDOI2016]征途(wqs二分+斜率优化)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4072 [SDOI2016]征途(wqs二分+斜率优化)相关的知识,希望对你有一定的参考价值。

LINK

n n n个数划分为 m m m段,求最小的方差.


设序列和 ∑ i = 1 n x i = S \\sum\\limits_{i=1}^nx_i=S i=1nxi=S,最后选取的每段的数字和为 L i L_i Li

D = 1 m ∗ ∑ i = 1 m ( E − L i ) 2 = 1 m ∑ i = 1 m ( E 2 + L i 2 − 2 E ∗ L i ) D=\\frac{1}{m}*\\sum\\limits_{i=1}^m(E-L_i)^2=\\frac{1}{m}\\sum\\limits_{i=1}^m (E^2+L_i^2-2E*L_i) D=m1i=1m(ELi)2=m1i=1m(E2+Li22ELi)

其中 E = S m E=\\frac{S}{m} E=mS

m ∗ D = m E 2 + ∑ i = 1 m L i 2 − 2 E ∗ ∑ i = 1 m L i m*D=mE^2+\\sum\\limits_{i=1}^mL_i^2-2E*\\sum\\limits_{i=1}^mL_i mD=mE2+i=1mLi22Ei=1mLi

m ∗ D = m E 2 + ∑ i = 1 m L i 2 − 2 m E 2 m*D=mE^2+\\sum\\limits_{i=1}^mL_i^2-2mE^2 mD=mE2+i=1mLi22mE2

得到 m 2 D = m ∗ ∑ i = 1 m L i 2 − S 2 m^2D=m*\\sum\\limits_{i=1}^mL_i^2-S^2 m2D=mi=1mLi2S2

如何最小化 ∑ i = 1 m L i 2 \\sum\\limits_{i=1}^m L_i^2 i=1mLi2??


定义 g ( i ) g(i) g(i)表示当 m = i m=i m=i时上式的最小值

大胆猜测是个斜率为负的下凸函数(分成一段肯定巨大,分成两段肯定变化显著,越往后分,减小的越慢)

这个下凸函数的斜率逐渐增大

考虑用一条斜率为 k k k的直线去切这个凸包,如何求出切点??

y = k x + b y=kx+b y=kx+b,因为是切线,所以让 b b b最小的点 ( x , g ( x ) ) (x,g(x)) (x,g(x))就是切点

那么 b = g ( x ) − k x b=g(x)-kx b=g(x)kx

我们的 x x x每增加 1 1 1, b b b值就会减小 k k k,也就是每段的权值会减去 k k k

现在的问题是可以分成任意段,求最小值

考虑定义 f [ i ] f[i] f[i]表示 [ 1 , i ] [1,i] [1,i]的分段代价

f [ i ] = min ⁡ { f [ j ] + ( p r e i − p r e j ) 2 − k } f[i]=\\min\\{f[j]+(pre_i-pre_j)^2-k\\} f[i]=min{f[j]+(preiprej)2k}

2 ∗ p r e i ∗ p r e j + f [ i ] + k − p r e i 2 = f [ j ] + p r e j 2 2*pre_i*pre_j+f[i]+k-pre_i^2=f[j]+pre_j^2 2preiprej+f[i]+kprei2=f[j]+prej2

斜率优化可以做到 O ( n ) O(n) O(n)

加上带权二分,总体复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

#include <bits/stdc++.h>
using namespace std;
const int maxn =3e3+10;
int n,m,f[maxn],pre[maxn],a[maxn],line[maxn];
int head = 1, tail = 0, q[maxn];
int x(int i){ return pre[i]; }
int y(int i){ return f[i]+pre[i]*pre[i]; }
double slove(int i,int j)
{
	return ( 1.0*y(i)-y(j) )/( 1.0*x(i)-x(j) );
}
int isok(int k)
{
	head = 1, tail = 0, q[++tail] = 0;
	for(int i=1;i<=n;i++)
	{
		while( head+1<=tail && slove(q[head],q[head+1])<2*pre[i] )	head++;
		int las = q[head];
		f[i] = f[las] +( pre[i]-pre[las] )[SDOI2016]征途

bzoj4518[Sdoi2016]征途 斜率优化dp

[SDOI2016]征途

luoguP4072 [SDOI2016]征途

题解SDOI2016征途

BZOJ4518[Sdoi2016]征途 斜率优化