[VIJOS P1037]搭建双塔
很不错的题啊……
很容易想到构造三维的状态,但无论时间还是空间都不好。我们可以构造[tex]f[i][delta][/tex]这种状态,表示用前[tex]i[/tex]块水晶,搭建出的双塔高度差为[tex]delta[/tex]时较大塔的高度。显然答案为[tex]f[n][0][/tex]。
转移的时候,要考虑放到高塔上还是低塔上,以及是否会导致高低塔地位对调。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=101,maxV=2001; int d[2][maxV]; int V[maxn]; int main(){ int n,maxj=0; register int i,j,now,pre; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&V[i]); maxj+=V[i]; } memset(d,-1,sizeof(d)); d[0][0]=0; for(i=1;i<=n;i++){ now=i%2; pre=1-now; for(j=0;j<=maxj;j++){ if(d[pre][j]>=0) d[now][j]=d[pre][j]; if(V[i]<=j){ if(d[pre][j-V[i]]>=0){ d[now][j]=max(d[now][j],d[pre][j-V[i]]+V[i]); } } if(V[i]>j && d[pre][V[i]-j]>=0){ d[now][j]=max(d[now][j],d[pre][V[i]-j]+j); } if(j+V[i]<=maxj && d[pre][j+V[i]]>=0) d[now][j]=max(d[now][j],d[pre][j+V[i]]); } } if(d[1&n][0]<=0) puts("Impossible"); else printf("%d\n",d[1&n][0]); return 0; }
[BZOJ 1756]小白逛公园
这题是很经典的线段树题。
我们可以发现最长子序列或跨越中点,或不跨越中点。若不跨越则肯定在左子或右子中,跨越则是左子最大后缀和和右子最大前缀和之和。问题便迎刃而解。(当然,求区间最大前缀/后缀和要用上区间和)
需注意此题可能会出现a>b!
代码:
/************************************************************** Problem: 1756 User: danihao123 Language: C++ Result: Accepted Time:2604 ms Memory:49648 kb ****************************************************************/ #include <cstdio> #include <algorithm> using namespace std; const int maxn=500001; struct Node{ int L,R; int maxP,maxS,ans,sum; }; Node Tree[maxn*4]; int A[maxn]; void merge(Node& O,Node& LC,Node& RC){ O.sum=LC.sum+RC.sum; O.maxP=max(LC.maxP,LC.sum+RC.maxP); O.maxS=max(RC.maxS,RC.sum+LC.maxS); O.ans=max(max(LC.ans,RC.ans),LC.maxS+RC.maxP); } void maintain(int o){ Node& O=Tree[o],LC=Tree[o<<1],RC=Tree[o<<1|1]; merge(O,LC,RC); } void build_tree(int o,int L,int R){ Node& O=Tree[o]; O.L=L; O.R=R; if(L==R){ O.maxP=O.maxS=O.ans=O.sum=A[L]; }else{ int M=L+(R-L)/2; build_tree(o<<1,L,M); build_tree(o<<1|1,M+1,R); maintain(o); } } void update(int o,int p,int v){ Node& O=Tree[o]; int& L=O.L,R=O.R; if(L==R){ O.maxP=O.maxS=O.ans=O.sum=v; }else{ int M=L+(R-L)/2; if(p<=M) update(o<<1,p,v); else update(o<<1|1,p,v); maintain(o); } } int ql,qr; Node query(int o){ Node& O=Tree[o]; int& L=O.L,R=O.R; if(ql<=L && R<=qr){ return Tree[o]; } int M=L+(R-L)/2; Node ANS,LC,RC; if(ql<=M){ LC=query(o<<1); if(qr>M){ RC=query(o<<1|1); merge(ANS,LC,RC); return ANS; }else{ return LC; } }else{ RC=query(o<<1|1); return RC; } } int main(){ int n,m; register int i; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&A[i]); build_tree(1,1,n); int k,a,b; Node ans; for(i=1;i<=m;i++){ scanf("%d%d%d",&k,&a,&b); if(k&1){ if(a>b) swap(a,b); ql=a; qr=b; ans=query(1); printf("%d\n",ans.ans); }else{ update(1,a,b); } } return 0; }