BZOJ3711 : [PA2014]Druzyny
设f[i]为[1,i]分组的最优解,则
f[i]=max(f[j]+1),max(c[j+1],c[j+2],...,c[i-1],c[i])<=i-j<=min(d[j+1],d[j+2],...,d[i-1],d[i])
设g[i]=min(j),i-j<=min(d[j+1],d[j+2],...,d[i-1],d[i])
容易发现g[i]单调不下降,可以通过线段树$O(n\log n)$预处理
考虑通过分治优化DP
在solve(l,r)时,求出[l+1,r]中c[]最大的位置,设为k
以k为分界线可以递归solve(l,k-1),solve(k,r)
然后只需用[l,k-1]的决策更新[k,r]即可
由于c[k]最大,所以c[k]<=i-j
i从max(c[k]+l,k)开始,决策j一开始的取值范围为[max(l,g[i]),i-c[k]]
每当i往右移一位时,j的上限也往右移一位,可以做到$O(1)$更新
j的下限可能也会右移到g[i],此时有l<=g[i]<=k-1,由于所有更新i的区间[l,k-1]均不相交
所以只存在一个区间[l,k-1]满足l<=g[i]<=k-1,即每个i最多只会发生一次下限右移
对于每次右移用线段树查询新区间内的最优解即可
当i循环到k+c[k]时,[k+c[k],r]内所有i的可行决策j的上限都为k-1,所以按g[]值将
[k+c[k],r]分割,对于每一段用线段树区间更新即可
总体复杂度为$O(n\log n)$。
#include<cstdio>
const int N=1000010,M=2097153,P=1000000007,inf=-1000000;
int n,i,j,c[N],d[N],g[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
inline int merge(int a,int b){return c[a]>c[b]?a:b;}
struct Num{
int x,y;
Num(){x=y=0;}
Num(int _x,int _y){x=_x,y=_y;}
inline Num operator+(Num b){
if(x<b.x)return b;
if(x>b.x)return Num(x,y);
return Num(x,(y+b.y)%P);
}
inline Num operator+(int _x){return Num(x+_x,y);}
inline void operator+=(Num b){*this=*this+b;}
}f[N];
struct Node{int c,d;Num f,tag;}T[M];
void build(int x,int a,int b){
if(a==b){
T[x].c=a;
T[x].d=d[a];
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
T[x].c=merge(T[x<<1].c,T[x<<1|1].c);
T[x].d=min(T[x<<1].d,T[x<<1|1].d);
}
void build2(int x,int a,int b){
T[x].tag=Num(inf,0);
if(a==b){
T[x].d=d[a];
T[x].f=f[a];
return;
}
int mid=(a+b)>>1;
build2(x<<1,a,mid),build2(x<<1|1,mid+1,b);
T[x].d=min(T[x<<1].d,T[x<<1|1].d);
T[x].f=T[x<<1].f+T[x<<1|1].f;
}
int askc(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return T[x].c;
int mid=(a+b)>>1;
if(d<=mid)return askc(x<<1,a,mid,c,d);
if(c>mid)return askc(x<<1|1,mid+1,b,c,d);
return merge(askc(x<<1,a,mid,c,d),askc(x<<1|1,mid+1,b,c,d));
}
int askd(int x,int a,int b,int c,int d){
if(c>d)return n+1;
if(c<=a&&b<=d)return T[x].d;
int mid=(a+b)>>1;
if(d<=mid)return askd(x<<1,a,mid,c,d);
if(c>mid)return askd(x<<1|1,mid+1,b,c,d);
return min(askd(x<<1,a,mid,c,d),askd(x<<1|1,mid+1,b,c,d));
}
void add(int x,int a,int b,int c,int d,Num p){
if(c<=a&&b<=d){T[x].tag=T[x].tag+p;return;}
int mid=(a+b)>>1;
if(c<=mid)add(x<<1,a,mid,c,d,p);
if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
}
Num askf(int x,int a,int b,int c,int d){
if(c>d)return Num(inf,0);
if(c<=a&&b<=d)return T[x].f;
int mid=(a+b)>>1;
if(d<=mid)return askf(x<<1,a,mid,c,d);
if(c>mid)return askf(x<<1|1,mid+1,b,c,d);
return askf(x<<1,a,mid,c,d)+askf(x<<1|1,mid+1,b,c,d);
}
inline Num askf1(int c){
int x=1,a=0,b=n,mid;Num t=Num(inf,0);
while(a!=b){
t+=T[x].tag;
mid=(a+b)>>1,x<<=1;
if(c<=mid)b=mid;else a=mid+1,x|=1;
}
return t+T[x].tag;
}
void change(int x,int a,int b,int c,Num p){
if(a==b){T[x].f=p;return;}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p);
T[x].f=T[x<<1].f+T[x<<1|1].f;
}
inline void update(int l,int k,int r){
int i=max(c[k]+l,k);
if(g[i]>=k||i>r)return;
int jl=max(l,g[i]),jr=i-c[k];
Num tmp=askf(1,0,n,jl,jr)+1;
for(;i<=k-1+c[k]&&i<=r;i++){
if(g[i]>jl){
if(g[i]>=k)return;
jl=g[i];
tmp=askf(1,0,n,jl,jr)+1;
}
f[i]+=tmp;
jr++;
if(jr>=jl)tmp+=f[jr]+1;
}
while(i<=r){
if(g[i]>jl){
if(g[i]>=k)return;
jl=g[i];
}
tmp=askf(1,0,n,jl,k-1)+1;
int t=askd(1,0,n,jl+1,n);
if(t>r){
add(1,0,n,i,r,tmp);
return;
}
add(1,0,n,i,t-1,tmp);
i=t;
}
}
void solve(int l,int r){
if(l==r){
if(l)change(1,0,n,l,f[l]=f[l]+askf1(l));
return;
}
int k=askc(1,0,n,l+1,r);
solve(l,k-1);
update(l,k,r);
solve(k,r);
}
int main(){
read(n);
for(i=1;i<=n;i++)read(c[i]),read(d[i]);
build(1,0,n);
for(i=0;i<=n;i++)d[i]=n+1,f[i]=Num(inf,0);
f[0]=Num(0,1);
for(i=0;i<=n;i++){
while(j<i&&i-j>askd(1,0,n,j+1,i))j++;
g[i]=j;
if(d[g[i]]>n)d[g[i]]=i;
}
build2(1,0,n);
solve(0,n);
if(f[n].x>0)printf("%d %d",f[n].x,f[n].y);else puts("NIE");
return 0;
}
BZOJ3711 : [PA2014]Druzyny的更多相关文章
- 【BZOJ3711】Druzyny
[BZOJ3711]Druzyny 题面 bzoj 题解 首先我们有一个\(O(n^2)\)的\(dp\): 设\(f_i\)表示现在已经分好了\(1...i\)的组,且\(i\)作为一组的结尾的最大 ...
- P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并
LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...
- [PA2014]Druzyny
题目描述 体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若干组,每一组都包含编号连续的一段小朋友,每个小朋友属于且仅属于一个组.第i个小朋友希望它所在的组的人数不多于d[i],不少于c ...
- @bzoj - 3711@ [PA2014]Druzyny
目录 @description@ @solution@ @accepted code@ @details@ @description@ 体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若 ...
- Work at DP
转载请注明出处:http://www.cnblogs.com/TSHugh/p/8858805.html Prepared: (无notes的波兰题目的notes见我的波兰题目补全计划)BZOJ #3 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- BZOJ3711 Druzyny 最大值分治、线段树
传送门 被暴力包菜了,然而还不会卡-- 有一个很暴力的DP:设\(f_i\)表示给\(1\)到\(i\)分好组最多可以分多少组,转移枚举最后一个组.接下来考虑优化这个暴力. 考虑:对于每一个位置\(i ...
- BZOJ 3721: PA2014 Final Bazarek
3721: PA2014 Final Bazarek Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 645 Solved: 261[Submit][ ...
- BZOJ 3709: [PA2014]Bohater
3709: [PA2014]Bohater Time Limit: 5 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1050 Solved: ...
随机推荐
- Unity 3D 关于给APK包加广告的流程
http://hunterwang.diandian.com/post/2012-11-23/40042217286 最近一直纠结着用Unity给安卓的应用添加广告,用Unity3d做安卓我还是第一次 ...
- previous_changes方法
[27] pry(main)> c = Channel.find 6 => #<Channel id: 6, title: "会员", cid: "96 ...
- 运行hexo提示/usr/bin/env: node: 没有那个文件或目录
由于Ubuntu下已经有一个名叫node的库,因此Node.js在ubuntu下默认叫nodejs,需要额外处理一下. 这个时候需要人为的建立链接,很简单一句话即可! sudo ln -s `whic ...
- Android mtk单路录音问题
在单路录音中,有两种情况导致底层录音资源被占用的问题: 1 开启vmLog后,拨打一个电话,挂断电话.如果挂断电话后,没有关闭vmlog进程,则会导致其它AP 无法得到底层的录音资源,从而无法录音. ...
- 2.10 用最少次数寻找数组中的最大值和最小值[find min max of array]
[本文链接] http://www.cnblogs.com/hellogiser/p/find-min-max-of-array.html [题目] 对于一个由N个整数组成的数组,需要比较多少次才能把 ...
- Java for LeetCode 060 Permutation Sequence
The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...
- Timer&TimerTask原理分析
转载地址,请珍惜作者的劳动成果,转载请注明出处:http://www.open-open.com/lib/view/open1337176725619.html 如果你使用Java语言进行开发,对于定 ...
- 越狱后天气闪退 iPhone5天气闪退解决方法
iPhone5天气闪退解决方法: 第一步:前往Cydia卸载AppSync; 第二步:通过iTools删除/var/mobile/Library/Caches/com.apple.mobile.ins ...
- 标准化css属性顺序
前言 对于css文件而言,选择器的写法有它的讲究,如—— 1> 不要用ID选择器 2> 不要用通配符*选择器 3> 选择器的层级 ...... 对于属性值的写法也有他的讲究,如—— ...
- Material Design风格登录注册
本文实现了以下功能 完整的代码和样例托管在Github 当接口锁定时,防止后退按钮显示在登录Activity 上. 自定义 ProgressDialog来显示加载的状态. 符合材料设计规范. 悬浮标签 ...