题目描述

体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若干组,每一组都包含编号连续的一段小朋友,每个小朋友属于且仅属于一个组。
第i个小朋友希望它所在的组的人数不多于d[i],不少于c[i],否则他就会不满意。
在所有小朋友都满意的前提下,求可以分成的组的数目的最大值,以及有多少种分组方案能达到最大值。

题解

现在假设不考虑C的限制,那么它的转移是一段连续的区间我们可以用单调队列求出来这一段区间。

加上C的限制以后,我们不好直接处理,所以考虑分治。

假设我们当前处理的区间为[l,r]那么我们考虑取[l+1,r]Cmax作为中点,先分治左边,在计算跨越区间的贡献。

如果我们这样直接算的话复杂度不对,是T(n)=T(x)+T(n-x)+n=n^2

考虑到T(n)=T(x)+T(n-x)+min(x,n-x)=nlogn

所以我们考虑优化一下转移。

现在我们假设[l,mid-1]都算完了,一开始的转移指针在max(l+c[mid],mid)

然后我们再用一对左右指针维护当前合法的转移点,然后用线段树维护答案。

每次转移指针往后动的时候,右指针也会往右动一个,我们的答案是支持增量的,所以可以O(1)维护。

但是左指针往右动的时候,我们的答案是不支持减法的,所以还要继续在线段树上查。

当右端点不能懂得时候,我们把不同种类的左端点分别批量操作就好了。

从网上看到了一个复杂度证明:

代码

#include <bits/stdc++.h>
#define N 1000005
using namespace std;
const int mod=;
int c[N],lef[N],n;
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct segmax{
int tr[N<<],id[N<<];
void build(int cnt,int l,int r){
if(l==r){tr[cnt]=c[l];id[cnt]=l;return;}
int mid=(l+r)>>;
build(cnt<<,l,mid);build(cnt<<|,mid+,r);
tr[cnt]=max(tr[cnt<<],tr[cnt<<|]);
id[cnt]=tr[cnt<<]>=tr[cnt<<|]?id[cnt<<]:id[cnt<<|];
}
void query(int cnt,int l,int r,int L,int R,int &ans1,int &ans2){
if(l>=L&&r<=R){
if(tr[cnt]>ans1){ans1=tr[cnt];ans2=id[cnt];}
return;
}
int mid=(l+r)>>;
if(mid>=L)query(cnt<<,l,mid,L,R,ans1,ans2);
if(mid<R)query(cnt<<|,mid+,r,L,R,ans1,ans2);
}
}T1;
struct node{
int mx,cnt;
node(int x=-1e9,int y=){mx=x;cnt=y;}
node operator +(const node &b)const{
if(mx==b.mx)return node(mx,(cnt+b.cnt)%mod);
else if(mx<b.mx)return b;else return *this;
}
node operator +(const int &b)const{return node(mx+b,cnt);}
}f[N];
struct segsum{
node tr[N<<],la[N<<];int ls[N<<],rs[N<<],ct;
segsum(){ct=;}
inline void pushdown(int cnt){
tr[ls[cnt]]=tr[ls[cnt]]+la[cnt];
tr[rs[cnt]]=tr[rs[cnt]]+la[cnt];
la[ls[cnt]]=la[ls[cnt]]+la[cnt];
la[rs[cnt]]=la[rs[cnt]]+la[cnt];
la[cnt]=node();
}
void build(int cnt,int l,int r){
if(l==r){if(l)tr[cnt]=node(-1e9,);else tr[cnt]=node(,);return;}
int mid=(l+r)>>;
rs[cnt]=++ct;ls[cnt]=++ct;
build(ls[cnt],l,mid);build(rs[cnt],mid+,r);
tr[cnt]=tr[ls[cnt]]+tr[rs[cnt]];
}
void upd(int cnt,int l,int r,int L,int R,node x){
if(l>=L&&r<=R){tr[cnt]=tr[cnt]+x;la[cnt]=la[cnt]+x;return;}
int mid=(l+r)>>;
if(la[cnt].cnt)pushdown(cnt);
if(mid>=L)upd(ls[cnt],l,mid,L,R,x);
if(mid<R)upd(rs[cnt],mid+,r,L,R,x);
tr[cnt]=tr[ls[cnt]]+tr[rs[cnt]];
}
void query(int cnt,int l,int r,int L,int R,node &x){
if(L>R)return;
if(l>=L&&r<=R){x=x+tr[cnt];return;}
int mid=(l+r)>>;
if(la[cnt].cnt)pushdown(cnt);
if(mid>=L)query(ls[cnt],l,mid,L,R,x);
if(mid<R)query(rs[cnt],mid+,r,L,R,x);
}
}T2;
inline int efs(int l,int r,int x){
int ans=;
while(l<=r){
int mid=(l+r)>>;
if(lef[mid]<=x)ans=mid,l=mid+;
else r=mid-;
}
return ans;
}
inline void work(int l,int mid,int r){
int i=max(c[mid]+l,mid);
int nowr=min(mid-,i-c[mid]),nowl=max(l,lef[mid]);node ans=node();
if(i>r||lef[i]>=mid)return;
T2.query(,,n,nowl,nowr,ans);if(ans.cnt)ans=ans+;
for(;i<=r;++i){
if(lef[i]>nowl){
if(lef[i]>=mid)return;
nowl=lef[i];
ans=node();
if(nowl<=nowr)T2.query(,,n,nowl,nowr,ans),ans=ans+;
}
f[i]=f[i]+ans;
nowr++;if(nowl<=nowr)ans=ans+(f[nowr]+);
if(nowr>mid-){nowr--;break;}
}
++i;
while(i<=r){
if(lef[i]>=nowl){
nowl=lef[i];
if(nowl>=mid)return;
}
ans=node();
T2.query(,,n,nowl,mid-,ans);if(ans.cnt)ans.mx++;
int t=efs(i,r,nowl);
T2.upd(,,n,i,t,ans);
i=t+;
}
}
void solve(int l,int r){
if(l>=r){node x=node();T2.upd(,,n,l,l,f[l]);T2.query(,,n,l,l,x);f[l]=x;return;}
int mx=,id=;
T1.query(,,n,l+,r,mx,id);
solve(l,id-);
work(l,id,r);
solve(id,r);
}
inline void prework(){
int q[N],d[N];
memset(q,,sizeof(q));memset(d,,sizeof(d));
n=rd();
for(int i=;i<=n;++i)c[i]=rd(),d[i]=rd();
int h=,t=,p=;
for(int i=;i<=n;++i){
while(h<=t&&d[q[t]]>=d[i])t--;
q[++t]=i;
while(h<=t&&i-p+>d[q[h]]){p++;while(h<=t&&q[h]<p)h++;}
lef[i]=p-;
}
}
int main(){
prework();
T1.build(,,n);
T2.build(,,n);
solve(,n);
node ans;
T2.query(,,n,n,n,ans);
if(!ans.cnt)puts("NIE");
else printf("%d %d",ans.mx,ans.cnt);
return ;
}

[PA2014]Druzyny的更多相关文章

  1. P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并

    LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...

  2. 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 ...

  3. @bzoj - 3711@ [PA2014]Druzyny

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若 ...

  4. Work at DP

    转载请注明出处:http://www.cnblogs.com/TSHugh/p/8858805.html Prepared: (无notes的波兰题目的notes见我的波兰题目补全计划)BZOJ #3 ...

  5. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  6. BZOJ 3721: PA2014 Final Bazarek

    3721: PA2014 Final Bazarek Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 645  Solved: 261[Submit][ ...

  7. BZOJ 3709: [PA2014]Bohater

    3709: [PA2014]Bohater Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1050  Solved: ...

  8. bzoj3714: [PA2014]Kuglarz

    [PA2014]KuglarzTime Limit: 20 Sec Memory Limit: 128 MBSubmit: 553 Solved: 317[Submit][Status][Discus ...

  9. 【贪心】bzoj 3709:[PA2014]Bohater

    3709: [PA2014]Bohater Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 653  Solved:  ...

随机推荐

  1. js判断时间是否超过了16:30

    // 判断时间是否超过了16:30 // true: 已超时 // false: 未超时 function timeCompare() { var now = new Date(); var nowT ...

  2. AngularJS学习之旅—AngularJS 模型(四)

    1.AngularJS ng-model 指令 1.ng-model 指令用于绑定应用程序数据到 HTML 控制器(input, select, textarea)的值. 2.ng-model 指令可 ...

  3. Cs231n课堂内容记录-Lecture 9 深度学习模型

    Lecture 9 CNN Architectures 参见:https://blog.csdn.net/qq_29176963/article/details/82882080#GoogleNet_ ...

  4. (一)走进Metasploit渗透测试框架

    渗透测试的流程 渗透测试是一种有目的性的,针对目标机构计算机系统安全的检测评估方法,渗透测试的主要目的是改善目标机构的安全性.渗透测试各个阶段的基本工作: 1.前期交互阶段 在这个阶段,渗透测试工程师 ...

  5. 删除网络中的本地连接*x等

    1.运行-regedit 打开注册表 定位到 HKEY_LOCAL_MACHINE SYSTEM CurrentControlSet Control Network {4D36E972-E325-11 ...

  6. ThinkPad E470笔记本电脑无声音、无线wifi功能(灰色)

    最近有同事找我看他的笔记本没有wifi,型号是ThinkPadE470 ,上网搜了下提问的挺多,写一个看看有什么帮助没 看了下笔记本wifi标志是灰色显示只有飞行模式,启用了一下热键 fn+F3 没什 ...

  7. Docker: 企业级镜像仓库Harbor的使用

    上一节,演示了Harbor的安装部署 这次我们来讲解 Harbor的使用. 我们需要了解到: 1. 如何推镜像到镜像仓库 2. 如何从镜像仓库拉取镜像 3. 如何运行从私有仓库拉取的镜像 # 查看 h ...

  8. Hadoop Compatibility in Flink

    18 Nov 2014 by Fabian Hüske (@fhueske) Apache Hadoop is an industry standard for scalable analytical ...

  9. supervisor管理php-fpm

    /etc/php-fpm.conf,设置daemonize = no,默认是yes

  10. 手把手教你实现Android RecyclerView上拉加载功能

    摘要 一直在用到RecyclerView时都会微微一颤,因为一直都没去了解怎么实现上拉加载,受够了每次去Github找开源引入,因为感觉就为了一个上拉加载功能而去引入一大堆你不知道有多少BUG的代码, ...