BZOJ3711: [PA2014]Druzyny
2017-12-15 09:26
393 查看
orz
考虑dp,f[i]表示1~i至多分成几段,g[i]表示1~i分成f[i]段的方案数
转移的时候将c[i],d[i]的限制分开考虑
对于d[i]的限制,不难发现他有单调性,可以预处理L[i]表示L[i]~i-1的j满足d[i]的限制可以由j转移到i
然后考虑c[i]的限制,他没有单调性,于是对c进行分治
如果我们在处理[l,r]这一个区间,找出[l+1,r]内c的最大值的位置k,那么k左边的j转移到i时,c值都是确定的c[k],接下来就是根据L[i],i,j的位置关系分情况讨论
先递归处理[l,k-1]的dp值,然后考虑[l,k-1]的j到[k,r]的i的转移
1:L[i]<=l,max(l+c[k],k)<=i<=min(k−1+c[k],r)
这种情况下随着i的右移,能贡献到i的j的集合每次增加一个元素,L[i]<=l的区间可以二分求O(logn),先用线段树查对左端点的贡献,然后i右移时可以O(1)更新,复杂度是O(较小的区间)
2:L[i]<=l,k−1+c[k]<=i<=r
可以直接线段树上区间更新i,复杂度O(logn)
3:l<L[i]<=k−1,k<=i<=r,二分求出i的取值范围,枚举i线段树查更新,因为分治的区间是不相交的,也就是说l<L[i]<=k−1对每个i只有一个这样的区间,因此这部分总复杂度是O(nlogn)的
因为总共O(n)个区间,总复杂度O(nlogn)
code:
考虑dp,f[i]表示1~i至多分成几段,g[i]表示1~i分成f[i]段的方案数
转移的时候将c[i],d[i]的限制分开考虑
对于d[i]的限制,不难发现他有单调性,可以预处理L[i]表示L[i]~i-1的j满足d[i]的限制可以由j转移到i
然后考虑c[i]的限制,他没有单调性,于是对c进行分治
如果我们在处理[l,r]这一个区间,找出[l+1,r]内c的最大值的位置k,那么k左边的j转移到i时,c值都是确定的c[k],接下来就是根据L[i],i,j的位置关系分情况讨论
先递归处理[l,k-1]的dp值,然后考虑[l,k-1]的j到[k,r]的i的转移
1:L[i]<=l,max(l+c[k],k)<=i<=min(k−1+c[k],r)
这种情况下随着i的右移,能贡献到i的j的集合每次增加一个元素,L[i]<=l的区间可以二分求O(logn),先用线段树查对左端点的贡献,然后i右移时可以O(1)更新,复杂度是O(较小的区间)
2:L[i]<=l,k−1+c[k]<=i<=r
可以直接线段树上区间更新i,复杂度O(logn)
3:l<L[i]<=k−1,k<=i<=r,二分求出i的取值范围,枚举i线段树查更新,因为分治的区间是不相交的,也就是说l<L[i]<=k−1对每个i只有一个这样的区间,因此这部分总复杂度是O(nlogn)的
因为总共O(n)个区间,总复杂度O(nlogn)
code:
#include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<cmath> #include<ctime> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long using namespace std; inline void read(int &x) { char c; int f=1; while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-1; x=c-'0'; while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0'; if(f==-1) x=-x; } const int maxn = 1010000; const int mod = 1000000007; void add(int &a,int b){a+=b;if(a>=mod)a-=mod;} int n; int c[maxn],d[maxn],L[maxn]; int t[maxn],ti[maxn],tp; struct node{int x,c;}f[maxn],zero; void upd(node &a,const node &b) { if(a.x<b.x) a.x=b.x,a.c=0; if(a.x==b.x) add(a.c,b.c); } struct segment{int ci;node f,flag;}seg[maxn<<2]; void build(const int x,const int l,const int r) { seg[x].f=seg[x].flag=zero; if(l==r) { seg[x].ci=l; return; } int mid=l+r>>1,lc=x<<1,rc=lc|1; build(lc,l,mid); build(rc,mid+1,r); seg[x].ci=c[seg[lc].ci]>=c[seg[rc].ci]?seg[lc].ci:seg[rc].ci; } node re; int loc; void updp(const int x,const int l,const int r) { upd(seg[x].f,f[loc]); if(l==r) { seg[x].f=f[l]; return; } int mid=l+r>>1,lc=x<<1,rc=lc|1; if(loc<=mid) updp(lc,l,mid); else updp(rc,mid+1,r); } void queryp(const int x,const int l,const int r) { upd(re,seg[x].flag); if(l==r)return; int mid=l+r>>1; if(loc<=mid) queryp(x<<1,l,mid); else queryp(x<<1|1,mid+1,r); } node fl; int lx,rx; void cover(const int x,const int l,const int r) { if(rx<l||r<lx) return; if(lx<=l&&r<=rx) { upd(seg[x].flag,fl);return; } int mid=l+r>>1; cover(x<<1,l,mid); cover(x<<1|1,mid+1,r); } void queryf(const int x,const int l,const int r) { if(rx<l||r<lx) return; if(lx<=l&&r<=rx) { upd(re,seg[x].f);return; } int mid=l+r>>1; queryf(x<<1,l,mid); queryf(x<<1|1,mid+1,r); } int queryc(const int x,const int l,const int r) { if(rx<l||r<lx) return 0; if(lx<=l&&r<=rx) return seg[x].ci; int mid=l+r>>1; int la=queryc(x<<1,l,mid),ra=queryc(x<<1|1,mid+1,r); if(c[la]==c[ra]) return la-l>r-ra?la:ra; return c[la]>c[ra]?la:ra; } void solve(const int l,const int r) { if(l==r) { re=zero; loc=l; queryp(1,0,n); upd(f[l],re); loc=l; updp(1,0,n); return; } lx=l+1,rx=r; int k=queryc(1,0,n),cc=c[k]; solve(l,k-1); int pl=k,pr=r; while(pl<=pr) { int mid=pl+pr>>1; if(L[mid]<=l) pl=mid+1; else pr=mid-1; }pl--; if(pl>=k) { int u=min(pl,k-1+cc); re=zero; lx=l,rx=max(k-cc,l); queryf(1,0,n); for(int j=max(k,l+cc);j<=u;j++) { if(re.x>=0) re.x++,upd(f[j],re),re.x--; if(j<u&&j+1-cc>=l) upd(re,f[j+1-cc]); } if(u<pl) { lx=u+1,rx=pl; fl=re; if(fl.x>=0) fl.x++,cover(1,0,n); } } int tmp=++pl; pr=r; while(pl<=pr) { int mid=pl+pr>>1; if(L[mid]<=k-1) pl=mid+1; else pr=mid-1; }pl--; if(L[pl]>l&&L[pl]<k) { pr=pl; pl=tmp; for(int j=pl;j<=pr;j++) { lx=L[j],rx=min(k-1,j-cc); if(lx<=rx) { re=zero; queryf(1,0,n); if(re.x>=0) re.x++,upd(f[j],re),re.x--; } } } solve(k,r); } int main() { zero=(node){-1,0}; read(n); for(int i=1;i<=n;i++) read(c[i]),read(d[i]); tp=0; int l=1; for(int i=1;i<=n;i++) { if(t[tp]>=d[i]) { t[tp]=d[i]; while(tp>1&&t[tp-1]>=t[tp]) t[--tp]=t[tp+1]; } else t[++tp]=d[i],ti[tp]=i; int j=L[i-1]; if(l>tp) l=tp; while(i-j>t[l]) { j++; if(l<tp&&j+1>=ti[l+1]) l++; } L[i]=j; } f[0]=(node){0,1}; for(int i=1;i<=n;i++) f[i]=zero; build(1,0,n); solve(0,n); //for(int i=1;i<=n;i++) printf("%d %d\n",f[i].x,f[i].c); if(f .x==-1) puts("NIE"); else printf("%d %d\n",f .x,f .c); return 0; }
相关文章推荐
- bzoj 3711: [PA2014]Druzyny 分治+线段树优化dp
- 【PA2014】【BZOJ3711】Druzyny
- BZOJ 3711 [PA2014]Druzyny
- [bzoj3711][PA2014]Druzyny【分治】【dp】
- 【set】bzoj3715 [PA2014]Lustra
- [BZOJ3714][PA2014]Kuglarz(MST)
- BZOJ3709 [PA2014]Bohater
- BZOJ 3721 PA2014 Final Bazarek 贪心
- bzoj3714: [PA2014]Kuglarz
- 【BZOJ】3714: [PA2014]Kuglarz
- BZOJ 3727 PA2014 Final Zadanie 树形DP
- bzoj 3709: [PA2014]Bohater 贪心
- [bzoj3717][PA2014]Pakowanie_动态规划_状压dp
- BZOJ3714: [PA2014]Kuglarz
- 【PA2014】【BZOJ3716】Muzeum
- BZOJ:3712: [PA2014]Fiolki
- BZOJ 3713: [PA2014]Iloczyn( 枚举 )
- BZOJ 3721 PA2014 Final Bazarek
- 【BZOJ3714】【PA2014】Kuglarz(最小生成树)
- 【贪心】bzoj 3709:[PA2014]Bohater