CF868F Yet Another Minimization Problem 決策單調性
阿新 • • 發佈:2021-01-11
題意:
顯然的 DP 式子 \(f_{i,j}=\min f_{k,j-1}+w(k,i)\)
滾掉第二維可以化簡為 \(g_i=\min f_k+w(k,i)\)
這個式子符合決策單調性,證明:
$\forall a<b<c<d\ w(a,c)+w(b,d)\le w(a,d)+w(b,c)且w(b,c)\le w(a,d) $
由於 \((b,c)\in(a,d)\) 所以 \(w(b,c)\le w(a,d)\) 所以第二個式子顯然成立
那麼我們開始推第一個式子
\(w(b,d)-w(b,c)\le w(a,d)-w(a,c)\)
我們記 \(val(x,y,z,w)\)
那麼原式等價於
\(val(b,c,c,d)\le val(a,c,c,d)\)
由於 \([b,c]\in[a,c]\) 所以 \([a,c]\) 中元素對數不少於 \([b,c]\) 中元素對數所以上式顯然成立
\(QED.\)
好,既然知道了 DP 可以斜率優化,那麼我們可以考慮 二分棧 或者 分治
由於二分棧有一個弊端就是必須能快速計算 \(w(i,j)\) 不然二分時統計答案複雜度過大就會白給,但不巧這個題不能快速計算 \(w(i,j)\) 所以我們只能採取分治寫法
每次劃分決策區間和二分割槽間,找最優決策點的時候只用暴力挪指標,開個桶更新一下相同元素對數,由於每個元素被挪次數不超過 \(\log\)
所以總複雜度是 \(O(n\log )\)
程式碼:
#include<bits/stdc++.h> using namespace std; namespace zzc { const int maxn = 1e5+5; long long f[25][maxn]; int a[maxn],num[maxn]; int n,m,cur,L,R; long long ans; void calc(int l,int r) { while(l<L) L--,ans+=num[a[L]],num[a[L]]++; while(R<r) R++,ans+=num[a[R]],num[a[R]]++; while(l>L) num[a[L]]--,ans-=num[a[L]],L++; while(R>r) num[a[R]]--,ans-=num[a[R]],R--; } void solve(int l,int r,int ll,int rr) { if(l>r) return ; int mid=(l+r)>>1,p; for(int i=ll;i<=min(mid,rr);i++) { calc(i+1,mid); if(f[cur-1][i]+ans<f[cur][mid]) { f[cur][mid]=f[cur-1][i]+ans; p=i; } } solve(l,mid-1,ll,p); solve(mid+1,r,p,rr); } void work() { memset(f,0x7f,sizeof(f)); scanf("%d%d",&n,&m);L=1; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) calc(1,i),f[1][i]=ans; for(int i=2;i<=m;i++) cur=i,solve(1,n,1,n); printf("%lld\n",f[m][n]); } } int main() { zzc::work(); return 0; }