1. 程式人生 > >codeforces #426 div2(The Bakery)834d

codeforces #426 div2(The Bakery)834d

題目連結
本菜感覺這個題目真是難,看了好久的題解才懂起,大致題意就是給一個數組,把陣列連續的分為k部分,每一部分的值等於這部分不同的數字的個數,要讓所有的值加起來最大,問怎樣分。

首先我們來看一下dp:
dp[i][j]表示前i個數字分成j組的的最優方案,那麼很容易就能夠得出一個狀態轉移公式
dp[i][j]=max(dp[t][j1]+F(t+1,i),j1<=t<i)其中F(x,y)表示x到y的分為一個區間的價值,但是複雜度完太高,於是這裡用線段樹來處理一下,最外層來列舉j,然後列舉i的時候有線段樹來優化,怎麼弄呢?
首先把線段樹用dp[x][j1],(0<=

x<=n)]來初始化,那麼線段樹就是維護的整個區間的最大值,然後更新當前狀態的時候,就從上一個和當前數字相等的數位置t 到 i-1區間的值都加1 然後當前最優的值就是0到i-1 區間的最大值,因為每次加一相當於從那個位置往後的區間多一個不同的數也就是當前的第j個區間的值,然後線段樹查詢就能過,最後答案就是dp[n][k]

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map> #include<queue> #include<stack> #include<cstring> #define clr(x) memset(x,0,sizeof(x)) using namespace std; #define LL long long const int N = 35005; struct TreeNode{ int ma; int cnt; }tree[N<<2]; int n; void PushUp(int now){ tree[now].ma = max(tree[now<<1
].ma,tree[now<<1|1].ma); } void PushDown(int now){ if(tree[now].cnt!=0) { int lson = now<<1; int rson = now<<1|1; tree[lson].cnt += tree[now].cnt; tree[lson].ma += tree[now].cnt; tree[rson].cnt += tree[now].cnt; tree[rson].ma += tree[now].cnt; tree[now].cnt = 0; } } void Update(int ul,int ur,int add,int l,int r,int now) { if(ul<=l && r <= ur) { tree[now].cnt += add; tree[now].ma += add; return; } PushDown(now); int mid = (l+r)/2; if(ul<=mid) Update(ul,ur,add,l,mid,now<<1); if(ur>mid) Update(ul,ur,add,mid+1,r,now<<1|1); PushUp(now); } int Query(int ql,int qr,int l,int r,int now) { if(ql <= l && r <= qr) { return tree[now].ma; } PushDown(now); int mid = (l+r)/2; int a1,a2; a1 = a2 = -9999999; if(ql<=mid) { a1 = Query(ql,qr,l,mid,now<<1); } if(qr>mid) { a2 = Query(ql,qr,mid+1,r,now<<1|1); } return max(a2,a1); } int dat[35005]; int dp[35005][55]; int last[35005]; int now[35005]; int main() { int k; while(scanf("%d%d",&n,&k)!=EOF) { clr(last); clr(now); for(int i = 1;i<=n;i++) { scanf("%d",&dat[i]); last[i] = now[dat[i]]; now[dat[i]] = i; } clr(dp); clr(tree); for(int i = 1;i<=k;i++) { clr(tree); for(int j = 1;j<=n;j++) { Update(j,j,dp[j][i-1],0,n,1); } for(int j = i;j<=n;j++) { Update(max(last[j],i-1),j-1,1,0,n,1); /* if(i==3) { for(int ii = 1;ii<=n;ii++) { cout << Query(ii,ii,0,n,1) << " "; } cout << endl; }*/ //if(i==3 && j)cout << j<<"kk" << Query(2,7,0,n,1) << endl; dp[j][i] = Query(i-1,j-1,0,n,1); } } printf("%d\n",dp[n][k]); } return 0; }