首页 > 学院 > 开发设计 > 正文

【JZOJ 4984】 太空飞船

2019-11-06 09:11:39
字体:
来源:转载
供稿:网友

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][j−1]+(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]<2∗s[i] 其中定义F(i,j)=f[k][j−1]+s[k]2+2∗avg∗s[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;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表