互测题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; }