1. 程式人生 > >Codeforces Round #426 (Div. 2) D. The Bakery(線段樹維護dp)

Codeforces Round #426 (Div. 2) D. The Bakery(線段樹維護dp)

src lap codeforce blank com date close scanf logs

題目鏈接: 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 }
View Code

Codeforces Round #426 (Div. 2) D. The Bakery(線段樹維護dp)