[CF868F] Yet Another Minimization Problem
阿新 • • 發佈:2019-01-08
Description
給定一個序列,要把它分成k個子序列。每個子序列的費用是其中相同元素的對數。求所有子序列的費用之和的最小值。
Solution
仍然是決策單調性的題目。
\(f[i][j]\)表示把前\(i\)個數分成\(j\)份的最小費用。
\[ f[i][j]=min(f[k][j-1]+w(k+1,i)) \]
顯然這個決策點是會單調遞減的,但是我們不能直接維護一個棧來完成了,因為\(w(k+1,i)\)是不能直接的算的。我們採用分治的做法,先找到\(f[mid][j]\)的決策點,然後分別算\([l,mid)\)和\((mid,r]\)的就行了。
Code
#include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } #define MN 100005 ll f[2][MN],a[MN],w[MN]; void solve(ll *F,ll *G,int l,int r,int ql,int qr,ll now) { if(l>r) return; register int i,k=0,mid=(l+r)>>1,p=min(mid,qr); for(i=l;i<=mid;++i) now+=w[a[i]]++; for(i=ql;i<=p;++i) now-=--w[a[i]],F[mid]>G[i]+now?F[mid]=G[i]+now,k=i:0; for(i=ql;i<=p;++i) now+=w[a[i]]++; for(i=l;i<=mid;++i) now-=--w[a[i]]; solve(F,G,l,mid-1,ql,k,now); for(i=l;i<=mid;++i) now+=w[a[i]]++; for(i=ql;i<k;++i) now-=--w[a[i]]; solve(F,G,mid+1,r,k,qr,now); for(i=ql;i<k;++i) ++w[a[i]]; for(i=l;i<=mid;++i) --w[a[i]]; } int main() { register int n=read(),k=read(),i; for(i=1;i<=n;++i) a[i]=read(); for(i=1;i<=n;++i) f[1][i]=f[1][i-1]+w[a[i]]++; memset(w,0,sizeof w); for(i=2;i<=k;++i) { memset(f[i&1],0x3f,sizeof f[i&1]); solve(f[i&1],f[(i-1)&1],1,n,1,n,0); } printf("%lld\n",f[k&1][n]); return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!