例
長さnの配列は、正の整数mをm ^ 2の最小分散することにより、セグメントに分割された各セグメントのシークと乗算されます。 - "SDOI2016の旅"
例-solve(偽)
配置された\(M \)セグメント長のセグメント\(X_I \) 、この場合、答えは
\ [M ^ 2 \ FRAC { \ sum_i(x_i- \バーX)^ 2} {M} = M \ sum_ix_i ^ 2〜2メートル\バーX \ sum_ix_i
+ M ^ 2 \バーX ^ 2 = M \ sum_ix_i ^ 2 - (\ sum_ix_i)^ 2 \] したがって、実際には、各セグメントの二乗和を最小化します。あなたは、その後に来て、暴力を書くことができます\(O(N ^ 2メートル) \) 優れたアルゴリズム。
加重半分
また、(x)は、厳密に最適化問題のk番目の決定の合計を解決するための凸最適化、WQS半分の勾配として知られている、G(x)は正確にX回の答えを聞かせて、G(x)は凸(G」を提示モノサイトゲネス又は単一ダウン)。
「加重」、いわゆる「2への権利を持つ」単純な理解は、意思決定の追加費用-cで、その後、(tにこの問題のニーズを決定を取るためにグラムの数と最適解のために必要な最小限の数に制限はありません最適解を計算します)高速解く、いわゆる「二」が所望の設定T kに等しいバイナリ重みによって運ばれます。
あまり直感的な?実際にはGの最大値の関数である横座標X0正接は、(X)横-CX(最小)点である場合、我々は凸関数G(x)およびY = CX +接点bを考えます。また、側面からの誘導体を説明した:Gの接点 'を(X0)= C、およびG'(x)は、単調である(G(x)は-CX) '= G'(x)-C存在ゼロX0ように。すなわち、それは重み付けバイナリCの接線の傾きを有し、この場合の最適解は、必要なT決定点x0を横軸として、何度も切断されます。
これは、私たちは、画像の面で機能することを可能にします?このプロセスを理解します。
トーク半分
スコープスロープ/ cは重量で何ですか?実際には限りCの範囲がリスト上のすべてのG(X + 1)-G(X)/ 1を含んでいます。もしG(X + 1)-G(X)/ 1が全て整数である場合、私たちも進整数ドメインをすることができます。
毎回ボールkと等しくすることができませんでした意思決定の少なくとも数、実際には、実際の答えは+ MC代わりにG + TCのgです。
凸決意
おそらくない非常に良い話題の凸部は、それを証明します。だから、あなたが使用することができますテーブル法を遊びますセンス法ような例は、(以降(x)をGの比(X + 1)が最適でないGは明らかである\((A + B)^ 2> 2 + A ^ B ^ 2 \)とG(X) G(x + 1)の)好ましくない比はG度合いよりも大きい(X + 1)Gよりも優れない(X + 2)度は、開口部G(x)は凸であるを促進することが考えられます。
例-solve
fを提供分散整数値2つのCドメインは、[i]を表すi番目の明確、前者の最小二乗およびいくつかのセクションに分割されているF [0] = 0、F [I] = F [J] +(S [I] -s [J])^ 2 + C。この最適化は、傾斜によって解決することができる; Gが配置された[I] [i]は、明らかにG F [i]が単調降下ではないことを決定の最小数を表します。このJ1そのようなものの存在が転送私ことを意味する場合、J2は[J1] [i]は、GからGで更新さを考慮して、より良いソリューションを取ることができます。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e3+10;
int n,m,q[N];
ll s[N],f[N],g[N];
inline double slope(int x,int y) {
return (double)(f[y]+s[y]*s[y]-f[x]-s[x]*s[x])/(s[y]-s[x]);
}
inline void check(int C) {
static int h,t;
q[h=t=0]=f[0]=g[0]=0;
for(int i=1; i<=n; ++i) {
while(h<t&&slope(q[h],q[h+1])<2*s[i]) ++h;
f[i]=f[q[h]]-C+(s[i]-s[q[h]])*(s[i]-s[q[h]]);
g[i]=g[q[h]]+1;
while(h<t&&slope(q[t-1],q[t])>slope(q[t],i)) --t;
q[++t]=i;
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i) {
scanf("%lld",s+i);
s[i]+=s[i-1];
}
int l=-s[n]*s[n],r=0,mid,C=0;
while(l<=r) {
mid=l+(r-l)/2; check(mid);
if(g[n]<=m) l=mid+1,C=mid;
else r=mid-1;
}
check(C);
printf("%lld\n",(f[n]+m*C)*m-s[n]*s[n]);
return 0;
}
右半分が非DP、そのようBZOJ2654のいくつかの最適化問題を行うことができますし、実際には、基本的な方法は、常に同じです。
私は、これは実際には2333年の講演で、それを期待していませんでした。