問題の意味
そこ\(N- \)非負整数\(a_iを\) \((N- \ 4 * 10 ^ル7)\) 、いくつかの部分に分割する、と呼ばれる(S_I \)\、必要(S_ {\ 1} + I \ GE S_I \) 、
提供\(RES = \ sum_ {I} = ^ {K}。1 S_I ^ 2 \) 。
需要\(RES \)最小
思考
64のPTS
実際の筆記試験。
セット\(F [I] [J ] \) 最初のセグメントの開始点である\(I \) 、終点\(J \)場合\(RES \)最低。
単純なアプローチは、直接列挙\(I 、J、K \) 、\(F [I] [J ] \) から\([J] F [K ] \) 上に移します。
最適化:
中間転写ポイント考えてみましょう\(J \)を、各\(I <J \) 、法的\(K \)の範囲が増加している、それだけで列挙することが可能である\(I、Jを\)その後、ポインタ\(K \)\(sum_j-sum_ {I- 1} \) 連続的に前進忘れ、及び最小値を更新することができます。
88のPTS
設けられている\(K \)ブロック、二つの特性を得ることができる。
自然の1:\(K \) 。より好ましい実施形態は、
知覚的に認識:\(A + B ^ 2 ^ 2 \ル(A + B)^ 2 \) 。
さらに推測
特性2:\(S_K \) 。小さい好ましい実施形態
知覚認識:\(S_Kが\)に正面を強制的に、正当なプログラムを作るために、小さい\(S \ )ので、可能な限り小さくなければならない\(A \)非負整数、(S \)\値が小さいほど、\(K \)以上、より好ましくは1プログラムの性質に応じ。
だから我々は最も小さい、それがエンドポイントであるときを見つけるために、それぞれのための単調なキューを維持することができる\(S_K \) 。
新しい要素は単調な詳細の一部としてだけでなくキューに追加されている場合は、コードを参照してください。
100pts
高精度を追加するための上記のアプローチ (高精度なものは長い...大丈夫、忘れてしまいました)
コード
64pts
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e3+7;
const ll inf=5e18;
int n,ty;
ll a[N],sum[N],f[N][N],ans=inf;
void read(){ }
ll p2(ll x){ return x*x; }
int main(){
//freopen("divd.in","r",stdin);
cin>>n>>ty;
if(ty) read();
else for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; }
memset(f,127,sizeof(f));
for(int i=1;i<=n;i++) f[i][n]=p2(sum[n]-sum[i-1]);
for(int j=n;j>=1;j--){
int k=n;
ll minx=inf;
for(int i=1;i<=j;i++){
while(p2(sum[j]-sum[i-1])<=p2(sum[k]-sum[j])){
minx=min(minx,f[j+1][k]);
k--;
}
f[i][j]=min(f[i][j],minx+p2(sum[j]-sum[i-1]));
}
}
for(int i=1;i<=n;i++) ans=min(ans,f[1][i]);
printf("%lld\n",ans);
return 0;
}
88pts
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e7+7;
int n,ty,pre[N],que[N],t1,t2;
ll a[N],sum[N],lst[N],ans;
void read(){};
ll p2(ll x){ return x*x; }
int main(){
// freopen("divd.in","r",stdin);
// freopen("x.out","w",stdout);
cin>>n>>ty;
if(ty) read();
else for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; }
t1=t2=1;
que[1]=0;
for(int i=1;i<=n;i++){
// printf("%d: ",i); for(int j=t1;j<=t2;j++) printf("%d ",que[j]); putchar('\n');
while(t1<t2&&lst[que[t1+1]]<=sum[i]-sum[que[t1+1]]) t1++;
pre[i]=que[t1];
lst[i]=sum[i]-sum[pre[i]];
while(t2>=t1&&lst[que[t2]]>=lst[i]+sum[i]-sum[que[t2]]) t2--;
que[++t2]=i;
}
int p=n;
while(p){
ans+=lst[p]*lst[p];
p=pre[p];
}
// for(int i=1;i<=n;i++) printf("pre[%d]: %d\n",i,pre[i]);
printf("%lld\n",ans);
return 0;
}