【JZOJ 4984】 太空飞船

来源:互联网 发布:淘宝桌游店 编辑:程序博客网 时间:2024/04/27 14:24

Description

这里写图片描述
这里写图片描述

Analysis

这个数据范围很显然的要分段程序

K=2

两段越平均越好,直接O(n)扫一遍即可

K=3

三段越平均越好,我们枚举其中一个等分点,调整另一个等分点(这个可以通过指针移动或二分来实现)。然后我们就有了两个等分点。但是这两个等分点的答案不一定是最优的。所以左边的等分点可能向右移一格。这会造成什么后果呢?右边的等分点会向右移动若干格。这个可以二分搞一波,然后整个过程就是O(nlogn)的
(我没打二分直接调整两个等分点向左右偏离一点点取min水过去了,面壁中)

K>3且N<=400

这个数据范围可以dp啦><
枚举圆环在哪个位置断开
状态很好设,f[i][j]表示前i个位置分了j段的最小值。
写出DP式子,就是

f[i][j]=min(f[k][j1]+(s[i]s[k]avg)2)(k<i)

s表示前缀和
O(n3k),爆炸
一看,嘿嘿嘿,这不是斜率优化标准形式吗,化简一下式子,两个决策k,l,k优于l当且仅当
g(k,l)=F(k,j)F(l,j)s[k]s[l]<2s[i]

其中定义F(i,j)=f[k][j1]+s[k]2+2avgs[k]
i递增
然后就是裸的斜率优化了,O(n2k)

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(ll i=a;i<=b;i++)using namespace std;typedef long long ll;const ll N=600005,M=22;const ll INF=9187201950435737471;ll n,k,avg,tot,a[N],b[N],f[405][M],s[N],q[N],S[N];ll sqr(ll x){return x*x;}ll F(int i,int j){    return f[i][j]+sqr(s[i])+2*avg*s[i];}ll G(int k,int l,int j){    return F(k,j)-F(l,j);}ll H(int k,int l){    return 2*(s[k]-s[l]);}ll dp(ll st){    fo(i,st,st+n-1) b[i-st+1]=a[i];    fo(i,1,n) s[i]=s[i-1]+b[i];    memset(f,0,sizeof(f));    f[0][0]=0;    fo(i,1,n) f[i][1]=sqr(s[i]-avg);    fo(j,2,k)    {        int head=1,tail=1;        q[1]=j-1;        fo(i,j,n)        {            while(head<tail && G(q[head+1],q[head],j-1)<s[i]*H(q[head+1],q[head])) head++;            f[i][j]=f[q[head]][j-1]+sqr(s[i]-s[q[head]]-avg);            while(head<tail && G(i,q[tail],j-1)*H(q[tail],q[tail-1])<G(q[tail],q[tail-1],j-1)*H(i,q[tail])) tail--;            q[++tail]=i;        }    }    return f[n][k];}int main(){    scanf("%lld %lld",&n,&k);    fo(i,1,n) scanf("%lld",&a[i]),a[i]*=k,tot+=a[i],a[n+i]=a[i],avg+=a[i];    fo(i,1,n+n) S[i]=S[i-1]+a[i];    avg/=k;    if(k==2)    {        ll ans=INF,sum=0,j=0;        fo(i,1,n)        {            sum-=a[i-1];            while(j<=i+n-1 && abs(sum-avg)>abs(sum+a[j+1]-avg)) sum+=a[++j];            ans=min(ans,sqr(sum-avg)+sqr(tot-sum-avg));        }        printf("%lld",ans);        return 0;    }    if(k==3)    {        ll ans=INF,sm=0,sm1=0,j=0,l=0;        fo(i,1,n)        {            sm-=a[i-1];            while(j<=i+n-1 && sm+a[j+1]<=avg) sm+=a[++j],sm1-=a[j];            if(j>l) l=j,sm1=0;            while(l<=i+n-3 && sm1+a[l+1]<=avg) sm1+=a[++l];            fo(p1,max(1ll,j-1),min(i+n-1,j+1))                fo(p2,max(p1+1,l-1),min(i+n-1,l+1))                {                    ll x=S[p1]-S[i-1],y=S[p2]-S[p1];                    ans=min(ans,sqr(x-avg)+sqr(y-avg)+sqr(tot-x-y-avg));                }        }        printf("%lld",ans);        return 0;    }    ll ans=INF;    fo(i,1,n) ans=min(ans,dp(i));    printf("%lld",ans);    return 0;}
0 0
原创粉丝点击