CF868 F. Yet Another Minimization Problem 決策單調優化 分治
阿新 • • 發佈:2018-10-10
efi getch 預處理 algo 單調性 代碼 arr 最優決策 ref ,而\([mid+1,r]\),的最優決策區間在\([p,R]\)上
分治下去
求解區間:\(|\gets預處理\to | l\frac{\qquad\qquad\qquad\downarrow^{mid}\qquad\qquad\qquad}{}r\)
題目鏈接
CF868F. Yet Another Minimization Problem
題解
\(f_{i,j}=\min\limits_{k=1}^{i}\{f_{k,j-1}+w_{k,i}\}\)
\(w_{l,r}\)為區間\([l,r]\)的花費,1D1D的經典形式
發現這個這是個具有決策單調性的轉移
單無法快速轉移,我們考慮分治
對於當前分治區間\([l,r]\) ,它的最優決策區間在\([L,R]\)之間。
對於\([l,r]\)的中點\(mid\),我們可以暴力掃\([L?mid]\)
找到mid的最優決策點p。因為決策單調,所以\([l,mid?1]\)最優決策區間為\([L,p]\)
分治下去
求解區間:\(|\gets預處理\to | l\frac{\qquad\qquad\qquad\downarrow^{mid}\qquad\qquad\qquad}{}r\)
決策區間:\(L\frac{\qquad\qquad\qquad\downarrow^{p}\qquad\qquad\qquad}{}R\)
代碼
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define gc getchar() #define pc putchar inline int read() { int x = 0,f = 1; char c = gc; while(c < '0' || c > '9' )c = gc; while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc; return x * f ; } void print(LL x) { if(x >= 10) print(x / 10); pc(x % 10 + '0'); } int n,K; const int maxn = 200007; int a[maxn],b[maxn],c[maxn]; LL f[maxn],dp[maxn]; void solve(int l,int r ,int L,int R,int w) { if(l > r) return ; int mid = l + r >> 1,k = 0,p = std::min(mid,R); for(int i = l;i <= mid;++ i) w += c[a[i]] ++; for(int i = L;i <= p;++ i) { w -= -- c[a[i]]; if(dp[mid] > f[i] + w) dp[mid] = f[i] + w,k = i; } for(int i = L;i <= p;++ i) w += c[a[i]] ++; for(int i = l;i <= mid;++ i) w -= --c[a[i]]; solve(l,mid - 1,L,k,w); for(int i = l;i <= mid;++ i) w += c[a[i]] ++; for(int i = L;i < k;++ i) w -= -- c[a[i]]; solve(mid + 1,r,k,R,w); for(int i = L;i < k;++ i) ++ c[a[i]]; for(int i = l;i <= mid;++ i) -- c[a[i]]; } int main() { n = read(),K = read(); for(int i = 1;i <= n;++ i) f[i] = f[i - 1] + c[a[i] = read()] ++; memset(c,0,sizeof c); for(int i = 1;i <= K;++ i) { memset(dp,0x3f,sizeof dp); solve(1,n,1,n,0); std::swap(f,dp); } print(dp[n]); return 0; }
CF868 F. Yet Another Minimization Problem 決策單調優化 分治