标签:tar ace pre 一个 scan namespace return target 转移
题目链接: Codeforces Round #426 (Div. 2) D. The Bakery
题意:
给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大。
题解:
考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp,
考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a[j],他只会影响last[a[j]]~j-1这段区间,所以线段树将这段区间加1。dp[i][j]就是区间最大值。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 inline int RT(int l,int r){return l+r|l!=r;} 4 using namespace std; 5 6 const int N=40000; 7 int n,k,mx[N*2],lazy[N*2],dp[N],a[N],la[N],pos[N]; 8 9 void build(int l=0,int r=n) 10 { 11 int rt=RT(l,r),mid=l+r>>1;lazy[rt]=0; 12 if(l==r){mx[rt]=dp[l];return;} 13 build(l,mid),build(mid+1,r); 14 mx[rt]=max(mx[RT(l,mid)],mx[RT(mid+1,r)]); 15 } 16 17 void PD(int l,int r) 18 { 19 int rt=RT(l,r),ls=RT(l,l+r>>1),rs=RT((l+r>>1)+1,r); 20 lazy[ls]+=lazy[rt],lazy[rs]+=lazy[rt]; 21 mx[ls]+=lazy[rt],mx[rs]+=lazy[rt]; 22 lazy[rt]=0; 23 } 24 25 void update(int L,int R,int v,int l=0,int r=n) 26 { 27 int rt=RT(l,r),mid=l+r>>1; 28 if(L<=l&&r<=R){mx[rt]+=v,lazy[rt]+=v;return;} 29 if(lazy[rt])PD(l,r); 30 if(L<=mid)update(L,R,v,l,mid); 31 if(R>mid)update(L,R,v,mid+1,r); 32 mx[rt]=max(mx[RT(l,mid)],mx[RT(mid+1,r)]); 33 } 34 35 int ask(int L,int R,int l=0,int r=n) 36 { 37 int rt=RT(l,r),mid=l+r>>1,ans=0; 38 if(L<=l&&r<=R)return mx[rt]; 39 if(lazy[rt])PD(l,r); 40 if(L<=mid)ans=max(ans,ask(L,R,l,mid)); 41 if(R>mid)ans=max(ans,ask(L,R,mid+1,r)); 42 return ans; 43 } 44 45 int main(){ 46 scanf("%d%d",&n,&k); 47 F(i,1,n)scanf("%d",a+i),pos[i]=la[a[i]],la[a[i]]=i; 48 F(i,1,k) 49 { 50 build(); 51 F(j,1,n)update(pos[j],j-1,1),dp[j]=ask(0,j-1); 52 } 53 printf("%d\n",dp[n]); 54 return 0; 55 }
Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)
标签:tar ace pre 一个 scan namespace return target 转移
原文地址:http://www.cnblogs.com/bin-gege/p/7276860.html