标签:不难 play 处理 优化 namespace ble str 时间 define
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4719
题目大意:有n个人,第$i$个人的身高为$h_i$,现在要把这些人按照原来的顺序分为连续的若干段,要求每组的人数不超过$l$,同时,我们这每组的最后一个人身高为$b_i$,则有$b_i>b_{i-1}(b_0=0)$,现在我们设每种分组方案的价值为$\sum b_{i}^{2}-b_{i-1}$,问能够得到的最大价值是多少?
Sample Input
2 5 2 1 4 3 2 5 5 2 5 4 3 2 1
Sample Output
Case #1: 31 Case #2: No solution
实际上最朴素的DP不难想到,设dp[i]表示前i个人分成若干组的最大价值,那么则有$dp[i]=max_{j=[i-l,i-1]}{dp[j]+h_i^2-h_j}$
那么代码也就不难写出来了:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mac=1e5+10; int dp[mac],h[mac]; int main() { int t,Case=0; scanf ("%d",&t); while (t--){ int n,m; scanf ("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf ("%d",&h[i]); memset(dp,0,sizeof dp); dp[1]=h[1]*h[1]; for (int i=1; i<=n; i++){ for (int j=max(1,i-m); j<i; j++){ if (h[j]>=h[i]) continue; dp[i]=max(dp[i],dp[j]+h[i]*h[i]-h[j]); } } if (!dp[n]) {printf("Case #%d: No solution\n",++Case);} else { printf("Case #%d: %d\n",++Case,dp[n]); } } return 0; }
只不过这样的话时间的复杂度会很高,就会导致T。。。
事实上将上面的式子变化一下就是:$dp[i]=h_i^2+max_{j=[i-l,i-1]}{dp[j]-h_j}$
而$max_{j=[i-l,i-1]}{dp[j]-h_j}$这个东西事实上可以用线段树来维护的,我们需要知道的是题目对顺序的要求,所以我们可以将他们的pos直接同步线段树的pos,那么这样一来查找的时候我们直接$query(1,n,1,pos[i]-l,pos[i]-1)$就可以了。那么怎么维护$b_i>b_{i-1}$呢,我们将其排序就好了,按照身高的升序排列,如果身高一样,则按照pos降序排列。因为后面的pos并不能影响前面的。
值得注意的是边界id的处理和爆int
以下是AC代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mac=1e5+10; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define lc rt<<1 #define rc rt<<1|1 typedef long long ll; struct node { int id,h; bool operator <(const node &a)const{ if (h==a.h) return id>a.id; return h<a.h; } }a[mac]; ll dp[mac]; ll tree[mac<<2]; void update(int l,int r,int rt,int pos,ll val) { if (l==r){ tree[rt]=val; return; } int mid=(l+r)>>1; if (mid>=pos) update(lson,pos,val); else {update(rson,pos,val);} tree[rt]=max(tree[lc],tree[rc]); } ll query(int l,int r,int rt,int L,int R) { ll ans=-1; if (l>=L && r<=R) return tree[rt]; int mid=(l+r)>>1; if (mid>=L) ans=max(ans,query(lson,L,R)); if (mid<R) ans=max(ans,query(rson,L,R)); return ans; } int main() { int t,Case=0; scanf ("%d",&t); while (t--){ int n,m,mx=0; scanf ("%d%d",&n,&m); for (int i=1; i<=n; i++){ int x; scanf ("%d",&x); a[i]=node{i+1,x}; } sort(a+1,a+1+n);n++; memset(dp,0,sizeof dp); memset(tree,-1,sizeof tree); ll ans=-1; update(1,n,1,1,0); for (int i=1; i<=n; i++){ ll p=query(1,n,1,max(1,a[i].id-m),a[i].id-1); if (p==-1) { if (a[i].id==n) break; continue; } dp[i]=1LL*a[i].h*a[i].h+p; if (a[i].id==n){ ans=dp[i]; break; } update(1,n,1,a[i].id,dp[i]-a[i].h); } if (ans==-1) printf("Case #%d: No solution\n",++Case); else printf("Case #%d: %lld\n",++Case,ans); } return 0; }
HDU-4719--Oh My Holy FFF(线段树优化DP)
标签:不难 play 处理 优化 namespace ble str 时间 define
原文地址:https://www.cnblogs.com/lonely-wind-/p/13245743.html