设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;
}

  

转载于:https://www.cnblogs.com/clrs97/p/4654215.html

BZOJ3711 : [PA2014]Druzyny相关推荐

  1. BZOJ3711: [PA2014]Druzyny

    orz 考虑dp,f[i]表示1~i至多分成几段,g[i]表示1~i分成f[i]段的方案数 转移的时候将c[i],d[i]的限制分开考虑 对于d[i]的限制,不难发现他有单调性,可以预处理L[i]表示 ...

  2. 【BZOJ 3711】[PA2014] Druzyny

    题目: Description 体育课上, n n n个小朋友排成一行(从 1 1 1到 n n n编号),老师想把他们分成若干组,每一组都包含编号连续的一段小朋友,每个小朋友属于且仅属于一个组. 第 ...

  3. 省选之前的未完成的计划(截至到省选)

    PLAN OF THE COMING HEOI good problems: -bzoj4823:[Cqoi2017]老C的方块 [*] -bzoj3171:[Tjoi2013]循环格 [*] -bz ...

  4. [bzoj3711]Druzyny

    题目描述 体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若干组,每一组都包含编号连续的一段小朋友,每个小朋友属于且仅属于一个组. 第i个小朋友希望它所在的组的人数不多于d[i],不少于 ...

  5. [PA2014]Pakowanie

    [PA2014]Pakowanie 题目大意: \(n(n\le24)\)个物品和\(m(m\le100)\)个背包,每个物体有一个体积\(a_i\),每个背包有一个容量\(c_i\).问装完所有物品 ...

  6. BZOJ3709: [PA2014]Bohater

    BZOJ3709: [PA2014]Bohater Description 在一款电脑游戏中,你需要打败n只怪物(从1到n编号). 为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药 ...

  7. bzoj 3714: [PA2014]Kuglarz

    3714: [PA2014]Kuglarz Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1151  Solved: 611 [Submit][St ...

  8. BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)

    显然可以dp:设f[i]为前i个人最多能分多少组,则f[i]=max{f[j]}+1 (cmax<=i-j<=dmin). 容易发现d的限制是一段连续区间,二分或者随便怎么搞都行.c则有点 ...

  9. bzoj 3709: [PA2014]Bohater

    3709: [PA2014]Bohater 链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3709 题面 在一款电脑游戏中,你需要打败n只怪物( ...

  10. [BZOJ]3727: PA2014 Final Zadanie

    题解:  我们可以得到 $  b[fa_i]+Sum-2*sz[i]=b[i] $ 然后我们把n-1条边的价值求和起来化简 $  (n-1)*Sum-2*b[1]=\sum_{i=2}^{n}b[i] ...

最新文章

  1. 51CTO学院薛大龙软考班,再努力一点点就能成功了
  2. SQL Server 中数据查询注意事项
  3. linux ubuntu 安装samba ftp nfs tftp,Ubuntu配置TFTP和NFS和samba服务配置.doc
  4. linux中ls命令
  5. 25种用户十秒离开你网站的原因!
  6. 【6】nagios从零学习使用 - centreon发送邮件报警
  7. 说说 Spring AOP 原理
  8. 12.2 asmca fails with 'ORA-00845'
  9. python批量从pdf中转换图片保存
  10. 【Spring第三篇】什么是Bean?
  11. 编写python程序、利用循环输出1+11+111+1111_《JavaScript语法基础》练习第四章第五题练习...
  12. 7-6 华氏度转摄氏度(四舍五入)
  13. 购买namesilo域名可以用微信支付了
  14. python统计图片数量_Python | 统计每个文件夹各类图片个数
  15. RTX3060(30系显卡)Windows10部署Pytorch深度学习环境步骤与心得
  16. 常用标点符号中英文对照表
  17. LeetCode-剑指Offe-32-1-从上到下打印二叉树
  18. 获取物料批次特性取值BAPI
  19. P2P流媒体直播点播(带宽节约95%以上)技术分享
  20. cocos2d粒子系统工具Particle Designer

热门文章

  1. C++ boost::upgrade_lock upgrade_to_unique_lock 升级锁 是什么 怎么用
  2. HTTPSConnectionPool(host=‘api.github.com‘, port=443): Max retries exceeded with url
  3. 基于SSM的理财系统
  4. kafka入门1-集群生产消息 报:ERROR Producer connection to localhost:9092 unsuccessful
  5. 直击面试,聊聊 GC 机制
  6. Ubuntu 15.04 或更新版 更新源/Ubuntu 15.04 Vivid Vervet更新源已可用
  7. Postman API 开发的协作平台
  8. Linux 之 CentOS 7.2 安装 Java JDK
  9. 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第6节 Lambda表达式_8_Lambda省略格式Lambda使用前...
  10. ActiveMQ学习笔记(1)----初识ActiveMQ