[SDOI2016]征途

题面描述

传送门

思路

方法一

方差

s 2 = ∑ i = 1 k ( v i − v ˉ ) 2 k s^2=\frac{\sum_{i=1}^k(v_i-\bar{v})^2}{k} s2=ki=1k(vivˉ)2

v ˉ = ∑ i = 1 k v i k \bar{v}=\frac{\sum_{i=1}^k v_i}{k} vˉ=ki=1kvi

s 2 = ∑ i = 1 k ( 1 k ∑ j = 1 k v j − v i ) 2 k s^2=\frac{\sum_{i=1}^k(\frac{1}{k}\sum_{j=1}^k v_j-v_i)^2}{k} s2=ki=1k(k1j=1kvjvi)2

s 2 = ∑ i = 1 k v i 2 + k ∗ ( ∑ j = 1 k v j k ) 2 − 2 ∗ ( ∑ j = 1 k v j ) 2 k k s^2=\frac {\sum_{i=1}^k v_i^2+k*(\frac{\sum_{j=1}^kv_j}{k})^2-2*\frac{(\sum_{j=1}^kv_j)^2}{k}}{k} s2=ki=1kvi2+k(kj=1kvj)22k(j=1kvj)2

s 2 = ∑ i = 1 k v i 2 + ( ∑ j = 1 k v j ) 2 k − 2 ∗ ( ∑ j = 1 k v j ) 2 k k s^2=\frac {\sum_{i=1}^k {v_i}^2+\frac{(\sum_{j=1}^kv_j)^2}{k}-2*\frac{(\sum_{j=1}^kv_j)^2}{k}}{k} s2=ki=1kvi2+k(j=1kvj)22k(j=1kvj)2

s 2 k 2 = k ∗ ∑ i = 1 k v i 2 − ( ∑ i = 1 k v i ) 2 s^2k^2=k*\sum_{i=1}^k{v_i}^2-(\sum_{i=1}^kv_i)^2 s2k2=ki=1kvi2(i=1kvi)2

状态转移方程

最终答案为 s 2 m 2 = m ∗ ∑ i = 1 m v i 2 − ( ∑ i = 1 m v i ) 2 s^2m^2=m*\sum_{i=1}^m{v_i}^2-(\sum_{i=1}^mv_i)^2 s2m2=mi=1mvi2(i=1mvi)2

( ∑ i = 1 m v i ) 2 (\sum_{i=1}^mv_i)^2 (i=1mvi)2是一个定值。

只需计算 ∑ i = 1 m v i 2 \sum_{i=1}^m{v_i}^2 i=1mvi2

s s s为长度前缀和,则

F i , p + 1 = min ⁡ ( F j , p + ( s i − s j ) 2 ) ( i > j ) F_{i,p+1}=\min(F_{j,p}+(s_i-s_j)^2)(i>j) Fi,p+1=min(Fj,p+(sisj)2)(i>j)

决策单调性

F j , p + ( s i − s j ) 2 ≥ F k , p + ( s i − s k ) 2 F_{j,p}+(s_i-s_j)^2\ge F_{k,p}+(s_i-s_k)^2 Fj,p+(sisj)2Fk,p+(sisk)2

对于未来状态 t t t,证明:

F j , p + ( s t − s j ) 2 ≥ F k , p + ( s t − s k ) 2 ∗ m F_{j,p}+(s_t-s_j)^2\ge F_{k,p}+(s_t-s_k)^2*m Fj,p+(stsj)2Fk,p+(stsk)2m

s t = s i + v a l ( v a l > 0 ) s_t=s_i+val(val>0) st=si+val(val>0)

只需证明:

− s j ≥ − s k -s_j\ge-s_k sjsk

s j &lt; s k s_j&lt; s_k sj<sk,证毕。

踢队头

F j , p + ( s i − s j ) 2 ≥ F k , p + ( s i − s k ) 2 F_{j,p}+(s_i-s_j)^2\ge F_{k,p}+(s_i-s_k)^2 Fj,p+(sisj)2Fk,p+(sisk)2

F j , p − 2 ∗ s i ∗ s j + s j 2 ≥ F k , p − 2 ∗ s i ∗ s k + s k 2 F_{j,p}-2*s_i*s_j+{s_j}^2\ge F_{k,p}-2*s_i*s_k+{s_k}^2 Fj,p2sisj+sj2Fk,p2sisk+sk2

F k , p − F j , p + s k 2 − s j 2 ≤ 2 ∗ s i F_{k,p}-F_{j,p}+{s_k}^2-{s_j}^2\le2*s_i Fk,pFj,p+sk2sj22si

c a l c ( j , k ) = F k , p − F j , p + s k 2 − s j 2 s k − s j ≤ 2 ∗ s i calc(j,k)=\frac{F_{k,p}-F_{j,p}+{s_k}^2-{s_j}^2}{s_k-s_j}\le 2*s_i calc(j,k)=sksjFk,pFj,p+sk2sj22si

k k k优于 j j j

c a l c ( q h e a d , q h e a d + 1 ) ≤ 2 ∗ s i calc(q_{head},q_{head+1})\le 2*s_i calc(qhead,qhead+1)2si

q h e a d + 1 q_{head+1} qhead+1优于 q h e a d q_{head} qhead,踢去 h e a d head head

维护一个 c a l c ( q h e a d , q h e a d + 1 ) ≥ 2 ∗ s i calc(q_{head},q_{head+1})\ge 2*s_i calc(qhead,qhead+1)2si队列

同时我们可以发现, c a l c ( q h e a d , q h e a d + 1 ) calc(q_{head},q_{head+1}) calc(qhead,qhead+1) 2 ∗ s i 2*s_i 2si的增大, h e a d head head不断增大,而不断增大。

因此,队列维护的应该是一个下凸壳。

踢队尾

由于维护一个下凸壳,

所以

c a l c ( q t a i l − 1 , q t a i l ) ≤ c a l c ( q t a i l , i − m ) calc(q_{tail-1},q_{tail})\le calc(q_{tail},i-m) calc(qtail1,qtail)calc(qtail,im)

反之,

c a l c ( q t a i l − 1 , q t a i l ) ≥ c a l c ( q t a i l , i − m ) calc(q_{tail-1},q_{tail})\ge calc(q_{tail},i-m) calc(qtail1,qtail)calc(qtail,im)

踢去队尾。

方法一 code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define gc getchar()
#define ll long long 
using namespace std;
const int N=3e3+10;
template<class orz>
inline void qr(orz &x)
{
    x=0;int f=1;char c=gc;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
    x*=f;
}
void qw(ll x)
{
    if(x<0)x=-x,putchar('-');
    if(x/10)qw(x/10);
    putchar(x%10+48);
}
ll f[N],g[N],ave;int s[N];
inline double calc(int j,int k)
{
    return (double)(g[k]-g[j]+s[k]*s[k]-s[j]*s[j])/(s[k]-s[j]);
}
int q[N],l,r;
int main()
{
    int n,m;qr(n);qr(m);
    for(int i=1;i<=n;i++)qr(s[i]),s[i]+=s[i-1];
    for(int i=1;i<=n;i++)f[i]=s[i]*s[i];
    for(int j=2;j<=m;j++)
    {
        memcpy(g,f,n<<3);l=1;r=1;q[1]=j-1;
        for(int i=j;i<=n;i++)
        {
            while(l<r&&calc(q[l],q[l+1])<=2.0*s[i])++l;
            while(l<r&&calc(q[r],i)<=calc(q[r-1],q[r]))--r;
            q[++r]=i;f[i]=g[q[l]]+(s[i]-s[q[l]])*(s[i]-s[q[l]]);
        }
    }
    qw(f[n]*m-s[n]*s[n]);
    return 0;
}

方法二

s s s为长度前缀和

仔细观察发现,貌似一天所走的路(从 j + 1 j+1 j+1走到 i i i)对最终答案的贡献为:

( s i − s j − a v e ) 2 ∗ m (s_i-s_j-ave)^2*m (sisjave)2m

那么,方程就为:

F i , p = min ⁡ ( F j . p − 1 + ( s i − s j − a v e ) 2 ∗ m ) F_{i,p}=\min(F_{j.p-1}+(s_i-s_j-ave)^2*m) Fi,p=min(Fj.p1+(sisjave)2m)

决策单调性

F j , p + ( s i − s j − a v e ) 2 ∗ m ≥ F k , p + ( s i − s k − a v e ) 2 ∗ m F_{j,p}+(s_i-s_j-ave)^2*m\ge F_{k,p}+(s_i-s_k-ave)^2*m Fj,p+(sisjave)2mFk,p+(siskave)2m

对于未来状态 t t t,证明:

F j , p + ( s t − s j − a v e ) 2 ≥ F k , p + ( s t − s k − a v e ) 2 ∗ m F_{j,p}+(s_t-s_j-ave)^2\ge F_{k,p}+(s_t-s_k-ave)^2*m Fj,p+(stsjave)2Fk,p+(stskave)2m

s t = s i + v a l ( v a l &gt; 0 ) s_t=s_i+val(val&gt;0) st=si+val(val>0)

只需证明:

− s j ≥ − s k -s_j\ge-s_k sjsk

s j &lt; s k s_j&lt; s_k sj<sk,证毕。

踢队头

F j , p + ( s i − s j − a v e ) 2 ∗ m ≥ F k , p + ( s i − s k − a v e ) 2 ∗ m F_{j,p}+(s_i-s_j-ave)^2*m\ge F_{k,p}+(s_i-s_k-ave)^2*m Fj,p+(sisjave)2mFk,p+(siskave)2m

F j , p + m ∗ ( ( s i − s j ) 2 − 2 ∗ ( s i − s j ) ∗ a v e + a v e 2 ) ≥ F k , p + m ∗ ( ( s i − s k ) 2 − 2 ∗ ( s i − s k ) ∗ a v e + a v e 2 ) F_{j,p}+m*((s_i-s_j)^2-2*(s_i-s_j)*ave+ave^2)\ge F_{k,p}+m*((s_i-s_k)^2-2*(s_i-s_k)*ave+ave^2) Fj,p+m((sisj)22(sisj)ave+ave2)Fk,p+m((sisk)22(sisk)ave+ave2)

F j , p + m ∗ ( − 2 ∗ s i ∗ s j + s j 2 + 2 ∗ s j ∗ a v e ) ≥ F k , p + m ∗ ( − 2 ∗ s i ∗ s k + s k 2 + 2 ∗ s k ∗ a v e ) ) F_{j,p}+m*(-2*s_i*s_j+{s_j}^2+2*s_j*ave)\ge F_{k,p}+m*(-2*s_i*s_k+{s_k}^2+2*s_k*ave)) Fj,p+m(2sisj+sj2+2sjave)Fk,p+m(2sisk+sk2+2skave))

F k , p − F j , p + m ∗ ( s k 2 − s j 2 + 2 ∗ a v e ∗ ( s k − s j ) ) ≤ 2 ∗ m ∗ s i ∗ ( s k − s j ) F_{k,p}-F_{j,p}+m*({s_k}^2-{s_j}^2+2*ave*(s_k-s_j))\le2*m*s_i*(s_k-s_j) Fk,pFj,p+m(sk2sj2+2ave(sksj))2msi(sksj)

c a l c ( j , k ) = F k , p − F j , p + m ∗ ( s k 2 − s j 2 + 2 ∗ a v e ∗ ( s k − s j ) ) s k − s j ≤ 2 ∗ m ∗ s i calc(j,k)=\frac{F_{k,p}-F_{j,p}+m*({s_k}^2-{s_j}^2+2*ave*(s_k-s_j))}{s_k-s_j}\le2*m*s_i calc(j,k)=sksjFk,pFj,p+m(sk2sj2+2ave(sksj))2msi

k k k优于 j j j

c a l c ( q h e a d , q h e a d + 1 ) ≤ 2 ∗ m ∗ s i calc(q_{head},q_{head+1})\le 2*m*s_i calc(qhead,qhead+1)2msi

q h e a d + 1 q_{head+1} qhead+1优于 q h e a d q_{head} qhead,踢去 h e a d head head

维护一个 c a l c ( q h e a d , q h e a d + 1 ) ≥ 2 ∗ m ∗ s i calc(q_{head},q_{head+1})\ge 2*m*s_i calc(qhead,qhead+1)2msi队列

同时我们可以发现, c a l c ( q h e a d , q h e a d + 1 ) calc(q_{head},q_{head+1}) calc(qhead,qhead+1) 2 ∗ m ∗ s i 2*m*s_i 2msi的增大, h e a d head head不断增大,而不断增大。

因此,队列维护的应该是一个下凸壳。

踢队尾

由于维护一个下凸壳,

所以

c a l c ( q t a i l − 1 , q t a i l ) ≤ c a l c ( q t a i l , i − m ) calc(q_{tail-1},q_{tail})\le calc(q_{tail},i-m) calc(qtail1,qtail)calc(qtail,im)

反之,

c a l c ( q t a i l − 1 , q t a i l ) ≥ c a l c ( q t a i l , i − m ) calc(q_{tail-1},q_{tail})\ge calc(q_{tail},i-m) calc(qtail1,qtail)calc(qtail,im)

踢去队尾。

方法2 code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define gc getchar()
#define ll long long 
using namespace std;
const int N=3e3+10;
template<class orz>
inline void qr(orz &x)
{
    x=0;int f=1;char c=gc;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
    x*=f;
}
void qw(ll x)
{
    if(x<0)x=-x,putchar('-');
    if(x/10)qw(x/10);
    putchar(x%10+48);
}
double f[N],g[N],ave;int s[N];
inline double calc(int j,int k)
{
    return (double)(g[k]-g[j]+s[k]*s[k]-s[j]*s[j]+2*ave*(s[k]-s[j]))/(s[k]-s[j]);
}
int q[N],l,r;
int main()
{
    int n,m;qr(n);qr(m);
    for(int i=1;i<=n;i++)qr(s[i]),s[i]+=s[i-1];ave=(double)s[n]/m;
    for(int i=1;i<=n;i++)f[i]=(s[i]-ave)*(s[i]-ave);
    for(int j=2;j<=m;j++)
    {
        memcpy(g,f,sizeof(g));l=1;r=1;q[1]=j-1;
        for(int i=j;i<=n;i++)
        {
            while(l<r&&calc(q[l],q[l+1])<=2.0*s[i])++l;
            while(l<r&&calc(q[r],i)<=calc(q[r-1],q[r]))--r;
            q[++r]=i;f[i]=g[q[l]]+(s[i]-s[q[l]]-ave)*(s[i]-s[q[l]]-ave);
        }
    }
    printf("%.0lf\n",f[n]*m);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值