BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)
显然可以dp:设f[i]为前i个人最多能分多少组,则f[i]=max{f[j]}+1 (cmax<=i-j<=dmin)。
容易发现d的限制是一段连续区间,二分或者随便怎么搞都行。c则有点麻烦,考虑分治。找到区间中c最大的位置,处理左边区间再向右边(包括该位置)转移,最后处理右边区间(当然就是cdq分治)。
考虑怎么转移。设当前区间为[l,r],分段点为k,处理的左边位置为i,右边位置j的限制区间为[aj,j-1],aj单调不降。若i能更新j,则满足i+ck<=j且i>=aj。显然j<l+ck或aj>=k的点是无法被转移到的。
讨论一波。对于aj<=l的区间,开始一段右端点每次+1,查询一次后每次O(1)更新;后面一段都是整个区间转移,直接在线段树上打标记。这样保证了是O(较小区间),也就保证了分治的复杂度。a[j]>l的暴力在线段树上查询,因为对于每个j这只会出现一次,复杂度也很正确。
不停地调分治结果发现线段树不停出锅,可能连线段树都不会写了,没救。(当然发现分治也出锅了
非常卡空间。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1000010 #define P 1000000007 int n,c[N],d[N],tree1[N<<2]; priority_queue<int,vector<int>,greater<int> > q,qdel; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} struct data{int x,y;}tree[N<<2],lazy[N<<2],f[N]; void upd(data &a,data b) { if (b.x>a.x) a=b; else if (b.x==a.x) inc(a.y,b.y); } void down(int k,int L,int R) { int mid=L+R>>1; upd(tree[k<<1],(data){lazy[k].x,1ll*(mid-L+1)*lazy[k].y%P}); upd(tree[k<<1|1],(data){lazy[k].x,1ll*(R-mid)*lazy[k].y%P}); upd(lazy[k<<1],lazy[k]); upd(lazy[k<<1|1],lazy[k]); lazy[k]=(data){0,0}; } data merge(data p,data q) { if (p.x<0&&q.x<0) return p; if (p.x>q.x) return p; else if (p.x<q.x) return q; return (data){p.x,(p.y+q.y)%P}; } data query(int k,int l,int r,int L,int R) { if (l>r) return (data){-N,0}; if (L==l&&R==r) return tree[k]; if (lazy[k].x) down(k,L,R); int mid=L+R>>1; if (r<=mid) return query(k<<1,l,r,L,mid); else if (l>mid) return query(k<<1|1,l,r,mid+1,R); else return merge(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R)); } void modify(int k,int l,int r,data p,int L,int R) { if (l>r) return; if (L==l&&R==r) { if (p.x>tree[k].x) tree[k].x=p.x,tree[k].y=1ll*p.y*(r-l+1)%P,lazy[k]=p; else if (p.x==tree[k].x) inc(tree[k].y,1ll*p.y*(r-l+1)%P),lazy[k].x=p.x,inc(lazy[k].y,p.y); return; } if (lazy[k].x) down(k,L,R); int mid=L+R>>1; if (r<=mid) modify(k<<1,l,r,p,L,mid); else if (l>mid) modify(k<<1|1,l,r,p,mid+1,R); else modify(k<<1,l,mid,p,L,mid),modify(k<<1|1,mid+1,r,p,mid+1,R); tree[k]=merge(tree[k<<1],tree[k<<1|1]); } int query2(int k,int l,int r,int L,int R) { if (L==l&&R==r) return tree1[k]; int mid=L+R>>1; if (r<=mid) return query2(k<<1,l,r,L,mid); else if (l>mid) return query2(k<<1|1,l,r,mid+1,R); else { int x=query2(k<<1,l,mid,L,mid),y=query2(k<<1|1,mid+1,r,mid+1,R); if (c[x]>c[y]) return x;else return y; } } void build(int k,int l,int r) { if (l==r) {tree1[k]=l;tree[k]=f[l];return;} int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree1[k]=c[tree1[k<<1]]>c[tree1[k<<1|1]]?tree1[k<<1]:tree1[k<<1|1]; tree[k]=merge(tree[k<<1],tree[k<<1|1]); } void pre() { int x=0; for (int i=1;i<=n;i++) { q.push(d[i]); while (!qdel.empty()&&q.top()==qdel.top()) q.pop(),qdel.pop(); while (q.top()+x<i) qdel.push(d[++x]); tree1[i]=x; } while (!q.empty()) q.pop(); while (!qdel.empty()) qdel.pop(); for (int i=1;i<=n;i++) d[i]=tree1[i]; build(1,0,n); } void solve(int l,int r) { if (l==r&&l) { data p=query(1,l,l,0,n); if (p.x<=f[l].x) modify(1,l,l,f[l],0,n); if (p.x>=f[l].x) upd(f[l],p); } if (l>=r) return; int k=query2(1,l+1,r,0,n); solve(l,k-1); if (d[k]<k) { data p=query(1,l,k-c[k]-1,0,n); for (int i=max(l+c[k],k);i<=r&&d[i]<=l&&i<=k-1+c[k];i++) { upd(p,f[i-c[k]]); upd(f[i],(data){p.x+1,p.y}); } int L=k,R=r,t=k-1; while (L<=R) { int mid=L+R>>1; if (d[mid]<=l) t=mid,L=mid+1; else R=mid-1; } modify(1,k+c[k],t,(data){p.x+1,p.y},0,n); for (int i=t+1;d[i]<=k-1&&i<=r;i++) { p=query(1,d[i],min(i-c[k],k-1),0,n); upd(f[i],(data){p.x+1,p.y}); } } solve(k,r); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3711.in","r",stdin); freopen("bzoj3711.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) c[i]=read(),d[i]=read(); f[0].x=0,f[0].y=1; for (int i=1;i<=n;i++) f[i].x=-N,f[i].y=0; pre(); solve(0,n); if (f[n].x>=0) cout<<f[n].x<<' '<<f[n].y<<endl; else cout<<"NIE"; return 0; }