【JZOJ 4984】太空飞船

来源:互联网 发布:it狂人第五季 编辑:程序博客网 时间:2024/04/27 19:22

Description

这里写图片描述

Solution

这道题化简以后就是要求把一个环分成K份,值得每份的平方之和最小;
这个的O(n^3m)的DP显然,
发现DP时几乎符合决策单调性,(不是全部)
所以可以用一个水法,
当然也可以用斜率优化,
还有一个分治的做法,因为每轮选的位置都是在上一次选的后面,
所以二分一个点,暴力找到它的最优位置,再把当前的区间分治下去,
复杂度多一个log,

Code

这个是水法

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define sqr(q) ((q)*(q))#define ZHI(t) (sqr(sum[t]-sum[L-1])+sqr(sum[R]-sum[t]))using namespace std;typedef long long LL;const int N=605005;int read(int &n){    char ch=' ';int q=0,w=1;    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());    if(ch=='-')w=-1,ch=getchar();    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;}int n,K;LL ans,P;int a[N];LL f[1000][55],sum[N];void ss(int q){    int mi;    memset(f,127,sizeof(f));    f[q-1][0]=0;    fo(i,q,n+q-1)f[i][1]=sqr(sum[i]-sum[q-1]);    fo(j,1,K-1)    {        mi=q-1+j;        fo(i,q+j,n+q-1)        {            fo(k,mi,i-1)            {                if(f[i][j+1]>f[k][j]+sqr(sum[i]-sum[k]))mi=k;                    else break;                f[i][j+1]=min(f[i][j+1],f[k][j]+sqr(sum[i]-sum[k]));            }        }    }}LL sf(int L,int R){    int l=L,r=R;    while(l+1<r)    {        int t=l+(r-l+1)/3,t1=l+(r-l+1)/3*2;        if(ZHI(t)>ZHI(t1))l=t+1;            else if(ZHI(t)<ZHI(t1))r=t1-1;                else l=t,r=t1;    }    return (ZHI(l)<ZHI(r))?ZHI(l):ZHI(r);}int MV(int q,LL w,LL e){    fo(i,q,n*2)if(w<=sum[i]-e)return i;    return n*2;}int main(){    read(n),read(K);    fo(i,1,n)P+=(a[i+n]=read(a[i]));    fo(i,1,n*2)sum[i]=sum[i-1]+a[i];    ans=1e16;    LL q=P*P*K-2*K*P*P;    if(K==3)    {        LL t=sum[n]/3;        int l=0,r=0;        fo(i,1,n)        {            l=MV(l,t,sum[i-1]);            r=MV(r,t*2,sum[i-1]);            fo(j,max(1,l-3),min(i+n-1,l+3))fo(k,max(1,r-3),min(i+n-1,r+3))                ans=min(ans,sqr(sum[j]-sum[i-1])+sqr(sum[k]-sum[j])+sqr(sum[i+n-1]-sum[k]));        }        printf("%lld\n",ans*K*K+q);        return 0;    }    if(K==2)    {        fo(i,1,n)            ans=min(ans,sf(i,n+i-1));        printf("%lld\n",ans*K*K+q);        return 0;    }    fo(i,1,n)    {        ss(i);        ans=min(ans,q+(LL)f[n+i-1][K]*K*K);    }    printf("%lld\n",ans);    return 0;}
0 0