BZOJ 3711 [PA2014]Druzyny
2017-03-02 07:37
369 查看
DP+分治+线段树
似乎有另一种O(nlogn)的做法,就不详细说了。说一种O(nlog2n)的做法。
考虑分治,对于区间[l,r],用[l,mid]来贡献[mid+1,r]。
对于一组贡献,设j∈[l,mid],i∈[mid+1,r]。
j 能贡献给i ,当且仅当,
max{l[k]|j<k≤mid}≤i−j≤min{r[k]|j<k≤mid}
max{l[k]|mid+1≤k≤i}≤i−j≤min{r[k]|mid+1≤k≤i}
移项一下,
max{l[k]|j<k≤mid}+j≤i≤min{r[k]|j<k≤mid}+j
i−min{r[k]|mid+1≤k≤i}≤j≤i−max{l[k]|mid+1≤k≤i}
不等号左右两边分别只和i,j有关,预处理一下。
对于第一个限制可以把j分成两个事件点max{l[k]|j<k≤mid}+j,min{r[k]|j<k≤mid}+j,一个加入,一个删除。对于第二个限制用线段树即可。
时间复杂度O(nlog2n),需要一定的常(底)数(层)优化技巧才能通过此题。反正我这样是没过。
似乎有另一种O(nlogn)的做法,就不详细说了。说一种O(nlog2n)的做法。
考虑分治,对于区间[l,r],用[l,mid]来贡献[mid+1,r]。
对于一组贡献,设j∈[l,mid],i∈[mid+1,r]。
j 能贡献给i ,当且仅当,
max{l[k]|j<k≤mid}≤i−j≤min{r[k]|j<k≤mid}
max{l[k]|mid+1≤k≤i}≤i−j≤min{r[k]|mid+1≤k≤i}
移项一下,
max{l[k]|j<k≤mid}+j≤i≤min{r[k]|j<k≤mid}+j
i−min{r[k]|mid+1≤k≤i}≤j≤i−max{l[k]|mid+1≤k≤i}
不等号左右两边分别只和i,j有关,预处理一下。
对于第一个限制可以把j分成两个事件点max{l[k]|j<k≤mid}+j,min{r[k]|j<k≤mid}+j,一个加入,一个删除。对于第二个限制用线段树即可。
时间复杂度O(nlog2n),需要一定的常(底)数(层)优化技巧才能通过此题。反正我这样是没过。
#include<cstdio> #include<algorithm> #define N 1000005 #define cmax(u,v) (u)<(v)?(u)=(v):0 #define cmin(u,v) (u)>(v)?(u)=(v):0 #define ainline __inline__ __attribute__((always_inline)) #define MOD 1000000007 #define reg register using namespace std; namespace runzhe2000 { namespace io { const int MaxBuff = 1 << 20; char B[MaxBuff], *S = B, *T = B; #define getc() ((S == T) && (T = (S = B) + fread(B, 1, MaxBuff, stdin), S == T) ? 0 : *S++) } ainline int read() { using namespace io; #define RG reg RG char ch; RG int ans = 0; RG bool neg = 0; while(ch = getc(), (ch < '0' || ch > '9') && ch != '-') ; ch == '-' ? neg = 1 : ans = ch - '0'; while(ch = getc(), '0' <= ch && ch <= '9') ans = ans * 10 + ch - '0'; return neg ? -ans : ans; } const int INF = 1<<29; struct event { int t, j, type; bool operator < (const event& that) const { if(t == that.t) return type > that.type; return t < that.t; } }ev[1500005]; int n, l , r , lm , rm ; struct Pair { int f, g; ainline void fuck(Pair& l, Pair& r) { *this=(l.f!=r.f?l.f>r.f?l:r:(Pair){l.f,(l.g+r.g)%MOD}); } ainline void operator += (const Pair& that) { if(f > that.f + 1) return; if(f <= that.f) *this = (Pair){that.f+1, that.g}; else (g += that.g) %= MOD; } }P , null; struct seg { Pair p; int c; }t[1<<20]; ainline int dmin(reg int a, reg int b){return a<b?a:b;} ainline int dmax(reg int a, reg int b){return a>b?a:b;} int ql, qr, qp; Pair *qpair; void build(reg int x, reg int l, reg int r) { t[x].p = null; t[x].c = 0; if(l == r) return; reg int mid = (l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } void query(reg int x, reg int l, reg int r) { if(!t[x].c) return; if(ql <= l && r <= qr) return (void) (*qpair += t[x].p); reg int mid = (l+r)>>1; if(ql <= mid) query(x<<1,l,mid); if(mid < qr ) query(x<<1|1,mid+1,r); } void modi(reg int x, reg int l, reg int r) { t[x].c += ((qpair->f < 0) ? -1 : 1); if(l == r){t[x].p = *qpair; return;} reg int mid = (l+r)>>1; (qp <= mid) ? modi(x<<1,l,mid) : modi(x<<1|1,mid+1,r); t[x].p.fuck(t[x<<1].p,t[x<<1|1].p); } void _solve(reg int L, reg int R, reg int mid) { lm[mid] = l[mid+1]; rm[mid] = r[mid+1]; for(int i = mid-1; i >= L; i--) lm[i] = dmax(lm[i+1], l[i+1]), rm[i] = dmin(rm[i+1], r[i+1]); for(int i = mid+1; i <= R; i++) lm[i] = dmax(lm[i-1], l[i]), rm[i] = dmin(rm[i-1], r[i]); reg int evcnt = 0; for(int j = L; j <= mid; j++) { if(lm[j] > rm[j] || P[j].f < 0) continue; ev[++evcnt] = (event){j+lm[j], j, 1}; ev[++evcnt] = (event){j+rm[j], j, -1}; } sort(ev+1, ev+1+evcnt); reg int oldcnt=evcnt; for(int i = mid+1; i <= R; i++) ev[++evcnt] = (event){i,i,0}; std::inplace_merge(ev+1,ev+1+oldcnt,ev+1+evcnt); build(1,L,mid); for(int i = 1; i <= evcnt; i++) { int j = ev[i].j; if(ev[i].type == 1) // add qp=j,qpair=P+j,modi(1,L,mid); else if(ev[i].type == -1) // del qp=j,qpair=&null,modi(1,L,mid); else if((ql=dmax(j-rm[j], L)) <= (qr=dmin(j-lm[j], mid))) qpair=P+j,query(1,L,mid); } } void solve(int L, int R) { if(L == R) return; reg int mid = (L+R)>>1; solve(L,mid); _solve(L,R,mid); solve(mid+1,R); } void main() { n = read(); null = (Pair){-INF,0}; for(int i = 1; i <= n; i++) { l[i] = read(), r[i] = read(); P[i] = null; } P[0] = (Pair){0,1}; solve(0,n); if(P .f > 0) printf("%d %d\n",P .f,P .g); else printf("NIE\n"); } } int main() { runzhe2000::main(); }
相关文章推荐
- BZOJ3711: [PA2014]Druzyny
- bzoj 3711: [PA2014]Druzyny 分治+线段树优化dp
- 【PA2014】【BZOJ3711】Druzyny
- [bzoj3711][PA2014]Druzyny【分治】【dp】
- bzoj 3709: [PA2014]Bohater
- [bzoj3712][PA2014]Fiolki_倍增LCA
- 【PA2014】【BZOJ3716】Muzeum
- 【BZOJ4619/3709】[Wf2016]Swap Space/[PA2014]Bohater 贪心
- BZOJ 3714 PA2014 Kuglarz Kruskal
- bzoj 3722: PA2014 Final Budowa
- bzoj 3714: [PA2014]Kuglarz 最小生成树
- BZOJ 3713 [PA2014]Iloczyn 枚举
- 【bzoj3714】[PA2014]Kuglarz
- BZOJ 3714 [PA2014]Kuglarz - 最小生成树模型
- BZOJ 3714 [PA2014]Kuglarz Kruskal
- 【PA2014】【BZOJ3713】Iloczyn
- bzoj 3725: PA2014 Final Matryca 乱搞
- bzoj 3717: [PA2014]Pakowanie
- BZOJ 3727 PA2014 Final Zadanie 树形DP
- BZOJ 3721 PA 2014 Final Bazarek 贪心