标签:
2 3 2 0 0 0 1 0 0 1 1 5 3 0 0 0 1 0 0 0 1 0 2 2 3 3 3
2 1 3 2HintIn the first case, RD can shoot the second ball at first and hit the third ball indirectly. In the second case, RD can shoot the second or the third ball initially and hit the fourth ball as well as the fifth ball. Two schemes are both the best.
比方我们要算[l,r]的dp值。mid=(L+r)/2如果我们已经算出了[l,mid]的dp值。我们是不是能够用[l,mid]的dp值去更新[mid+1,r]的dp值。
由于dp[i]一定是由1~i-1转移来的所以我们能够建一个树状数组维护z值为zz的最大dp(由于这题每次都是查询[1,x]整个区间所以能够用树状数组来维护最值)。当然z值是离散化后的值。然后我们两边的y排序.然后对于[mid+1,r]的每个dp我们按y值从小到大更新。先把[l,mid]中y值比自己小的插到树状数组中。
然后查询数组数组中z小于自己z的最大dp即可了。这样就能够保证树状数组中的元素x,y都是合理的然后查询的z也是合理的。然后递归处理即可了。先solve(l,mid)然后更新[mid+1,r]再solve(mid+1,r)。
当然递归的时候也能够顺便进行一些排序操作(归并排序)以提高效率。
#include<algorithm> #include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100010; const int mod=1<<30; typedef long long ll; struct node { int x,y,z; inline bool operator <(const node& tt) const { if(x!=tt.x) return x<tt.x; if(y!=tt.y) return y<tt.y; return z<tt.z; } } po[maxn]; int dp[maxn],sy[maxn],sz[maxn],mv[maxn],ans; int tmp[maxn<<1],ty[maxn],ptr; ll num[maxn],nv[maxn],ansn; bool cmp(int a,int b)//注意y必须这么排.不然可能出现y相等的时候i+1排到i前面的情况. { if(po[a].y!=po[b].y) return po[a].y<po[b].y; return a<b; } void update(int x,int v,ll d,int mn) { for(int i=x;i<=mn;i+=i&-i) { if(v>mv[i]) mv[i]=v,nv[i]=d; else if(v==mv[i]) nv[i]+=d; } } int qu(int x,ll &nn) { int ret=0; for(int i=x;i>0;i-=i&-i) { if(ret<mv[i]) ret=mv[i],nn=nv[i]; else if(mv[i]==ret) nn+=nv[i]; } return ret; } void solve(int l,int r) { if(l==r) { if(dp[l]>ans) ans=dp[l],ansn=num[l]; else if(dp[l]==ans) ansn+=num[l]; sz[l]=po[l].z; return; } int mid=(l+r)>>1,le=l,ri=mid+1,len=r-l+1,ml=mid-l+1,lim,h,i; memmove(tmp+ptr,sy+l,len*sizeof(int)); for(i=0;i<len;i++) if(tmp[ptr+i]<=mid)//直接把排好的序划分下去即可了。sy[le++]=tmp[ptr+i]; else sy[ri++]=tmp[ptr+i]; ptr+=len; solve(l,mid); lim=ptr,ptr-=len; for(i=1;i<=ml;i++) mv[i]=0; for(i=ptr;i<lim;i++) { if(tmp[i]<=mid) { h=lower_bound(sz+l,sz+l+ml,po[tmp[i]].z)-(sz+l)+1; update(h,dp[tmp[i]],num[tmp[i]],ml); continue; } h=lower_bound(sz+l,sz+l+ml,po[tmp[i]].z)-(sz+l); if(h>=ml||sz[l+h]>po[tmp[i]].z) h--; if(h>=0) { ll cc=0; int tt=qu(h+1,cc)+1; if(tt>dp[tmp[i]]) dp[tmp[i]]=tt,num[tmp[i]]=cc; else if(tt==dp[tmp[i]]&&tt!=1) num[tmp[i]]+=cc; } } solve(mid+1,r); merge(sz+l,sz+l+ml,sz+l+ml,sz+l+len,ty); memmove(sz+l,ty,len*sizeof(int)); } int main() { int t,n,i; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].z); ansn=ptr=ans=0; sort(po+1,po+n+1); for(i=1;i<=n;i++) sy[i]=i,dp[i]=1,num[i]=1; sort(sy+1,sy+n+1,cmp); solve(1,n); printf("%d %I64d\n",ans,ansn%mod); } return 0; } /* 送一组数据。网上好多代码都过不了这组。就是由于排序y的时候i+1排到i前面去了。导致少更新非常多 杭电数据比較水就水过去了。
1 17 2 0 0 2 1 1 1 2 1 1 0 0 0 0 1 0 2 0 0 2 2 0 1 1 2 0 1 1 2 2 0 1 0 2 0 2 2 2 2 0 1 2 1 0 2 1 1 1 0 0 2 */
hdu 4742 Pinball Game 3D(三维LIS&cdq分治&BIT维护最值)
标签:
原文地址:http://www.cnblogs.com/gcczhongduan/p/5349870.html