互測題T3...ios
首先有個dp是很是好想的:數組
設dp[i][j]爲前j個數分紅i組的最大得分,則易得:dp[i][j]=max{dp[i-1][k-1]+num[k][j]},其中,num[k][j]表示從第k個數到第j個數不一樣值的數量ui
而num數組能夠預處理出來,時間複雜度O(n^2 k)spa
等等,這樣好像過不掉這道題啊code
咱們發現,max{dp[i-1][k-1]+num[k][j]}這個東西是否是應該用什麼維護一下?blog
線段樹!string
利用線段樹,咱們能夠實現區間求最值!it
咱們記錄一個位置i上的數a[i]上一次出現的位置爲las[i],那麼當咱們更新dp到位置i時,咱們就能夠進行轉移,而若是一共分了k組,則最後這一組的起點必定在k之後!io
同時,利用las[i],咱們能夠將las[i]+1~i這一整段區間的值所有+1,由於這一段區間在更新dp時不產生重複class
最後咱們在k~i這段區間上作區間查詢,求最大值即爲dp值
每次更新完一組的dp值之後,都須要從新建樹,相似滾動數組的原理
還有,在建樹時,考慮到轉移方程中須要用到的是dp[i-1][k-1],因此在建樹時賦值的下標都應當-1以便利用
代碼:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define rt1 rt<<1 #define rt2 (rt<<1)|1 #define ls tree[rt].lson #define rs tree[rt].rson using namespace std; struct Tree { int lson; int rson; int maxval; int lazy; }tree[400005]; int dp[55][35005]; int las[35005]; int p[35005]; int n,k; void buildtree(int l,int r,int rt,int typ) { ls=l; rs=r; tree[rt].lazy=0; if(l==r) { tree[rt].maxval=dp[typ][l-1]; return; } int mid=(l+r)>>1; buildtree(l,mid,rt1,typ); buildtree(mid+1,r,rt2,typ); tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval); } void pushdown(int rt) { int t=tree[rt].lazy; tree[rt].lazy=0; tree[rt1].lazy+=t; tree[rt2].lazy+=t; tree[rt1].maxval+=t; tree[rt2].maxval+=t; } void ins(int l,int r,int v,int rt) { if(ls>r||rs<l) { return; } if(ls>=l&&rs<=r) { tree[rt].lazy+=v; tree[rt].maxval+=v; return; } pushdown(rt); int mid=(ls+rs)>>1; if(l<=mid) { ins(l,r,v,rt1); } if(r>mid) { ins(l,r,v,rt2); } tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval); } int query(int l,int r,int rt) { if(l>rs||r<ls) { return 0; } if(l<=ls&&r>=rs) { return tree[rt].maxval; } pushdown(rt); return max(query(l,r,rt1),query(l,r,rt2)); } int main() { // freopen("handsome.in","r",stdin); // freopen("handsome.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); las[i]=p[x]; p[x]=i; } buildtree(1,n,1,0); for(int i=1;i<=k;i++) { for(int j=1;j<=n;j++) { int lq=las[j]; ins(lq+1,j,1,1); dp[i][j]=query(i,j,1); } buildtree(1,n,1,i); } printf("%d\n",dp[k][n]); return 0; }