题目

题目大意

给你一串二元组\((a_i,b_i)\)的数列。

求最小的区间\([l,r]\)长度,满足\([l,r]\)中的每个二元组选或不选,使得\(\sum a_i=w\)且\(\sum b_i\leq k\)


思考历程

想了好久,想来想去都是一个背包……

最终决定打暴力……


正解

先说说GMH大爷的神奇解法。

首先是二分答案\(ans\),转化成判定问题。然后在数列中每\(ans\)个点设置一个观测点。

以每个观测点为中心,向左和向右背包,然后合并。

然而正解并不需要一个\(\log\)

考虑双指针,就是记一个当前的最佳答案\(ans\),后面的区间长度都要小于\(ans\)。脑补一下这个过程,其实这就是一个队列,只需要支持左边出右边入的队列。

但是背包问题不满足可减性。于是就有个非常骚的解法:

把这个队列用两个栈来代替,栈顶分别为队头和队尾。

加入的时候,就在第二个栈的栈顶加入;弹出的时候,就直接弹出第一个栈的栈顶。

如果第一个栈为空,那就将第二个栈里的东西倒过来放到第一个栈中,然后暴力重构。

每个元素只会暴力重构一次,所以不会时间超限。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 10010
#define maxW 5010
inline int input(){
char ch=getchar();
while (ch<'0' || '9'<ch)
ch=getchar();
int x=0;
do{
x=x*10+ch-'0';
ch=getchar();
}
while ('0'<=ch && ch<='9');
return x;
}
int n,W,K,a[N],b[N];
int f[N][maxW];
int st1[N],top1,st2[N],top2;
inline void update(int &a,int b){a>b?a=b:0;}
inline bool ok(int j){
int jj=st1[top1];
for (int k=0;k<=W;++k)
if (f[jj][k]+f[j][W-k]<=K)
return 1;
return 0;
}
int main(){
freopen("cactus.in","r",stdin);
freopen("cactus.out","w",stdout);
n=input(),W=input(),K=input();
for (int i=1;i<=n;++i)
a[i]=input(),b[i]=input();
int ans=n+1;
f[0][0]=0;
for (int i=1;i<=W;++i)
f[0][i]=K+1;
for (int i=1,j=1;i<=n;++i){
if (ok(st2[top2]))
ans=j-i;
for (;j<=n && j-i+1<ans;++j){
st2[++top2]=j;
int lst=st2[top2-1];
memcpy(f[j],f[lst],sizeof(int)*(W+1));
for (int k=0;k+a[j]<=W;++k)
update(f[j][k+a[j]],f[lst][k]+b[j]);
if (ok(j))
ans=j-i+1;
}
if (!top1){
for (int j=top2;j>=1;--j)
st1[++top1]=st2[j];
top2=0;
for (int j=1;j<top1;++j){
int now=st1[j],lst=st1[j-1];
memcpy(f[now],f[lst],sizeof(int)*(W+1));
for (int k=0;k+a[now]<=W;++k)
update(f[now][k+a[now]],f[lst][k]+b[now]);
}
}
top1--;
}
if (ans==n+1)
printf("-1\n");
else
printf("%d\n",ans);
return 0;
}

总结

还有这么骚的栈操作……

这告诉我们有时候维护队列的东西可以用两个栈来搞。

6358. 【NOIP2019模拟2019.9.15】小ω的仙人掌的更多相关文章

  1. 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)

    题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...

  2. [JZOJ6359] 【NOIP2019模拟2019.9.15】小ω的树

    题目 题目大意 给你一棵树,带点权和边权. 要你选择一个联通子图,使得点权和乘最小边权最大. 支持修改点权操作. 思考历程 显然,最先想到的当然是重构树了-- 重构树就是在做最大生成树的时候,当两个联 ...

  3. 6389. 【NOIP2019模拟2019.10.26】小w学图论

    题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...

  4. 6380. 【NOIP2019模拟2019.10.06】小w与最长路(path)

    题目 题目大意 给你一棵树,对于每一条边,求删去这条边之后,再用一条边(自己定)连接两个连通块,形成的树的直径最小是多少. 正解 首先,将这棵树的直径给找出来.显然,如果删去的边不在直径上,那么答案就 ...

  5. 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋

    题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...

  6. 6407. 【NOIP2019模拟11.05】小 D 与随机

    题目描述 Description Input 第一行两个个整数 n,k. 之后 n -1 行,第 i 行两个整数 ui, vi, 表示一条树边. 保证输入的数据构成一棵树. Output 一行一个数表 ...

  7. 6392. 【NOIP2019模拟2019.10.26】僵尸

    题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...

  8. 6364. 【NOIP2019模拟2019.9.20】养马

    题目描述 题解 一种显然的水法:max(0,-(点权-边权之和*2)) 这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值 考虑从子树往上推求出当前点的答案 设每棵子树从根往 ...

  9. 6362. 【NOIP2019模拟2019.9.18】数星星

    题目描述 题解 一种好想/好写/跑得比**记者还快的做法: 对所有询问排序,按照R递增的顺序来处理 维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和 LCT随便覆 ...

随机推荐

  1. Linux中目录结构以及VI编辑器常见的命令操作

    1.每个目录的详细介绍,先放一张目录的整体结构在这里 /bin:是Binary的缩写,用于存放经常使用的命令 /sbin:s代表Super User,用于存放系统管理员使用的命令 /home:存放普通 ...

  2. 路由网关--spring cloud zuul

    路由网关--spring boot Zuul 1.为什么需要Zuul? Zuul Ribbon 以及 Eureka 相结合,可以实现智能路由和负载均衡的功能, Zuul 能够将请求流量按某种策略分发到 ...

  3. 57. Collections(list的工具类)、Arrays(数组的工具类)

    List集合的工具类(Collections): 注意:Collection是单列集合的根接口  Collections是操作集合对象的工具类 1.对list集合排序: sort(List) 根据自然 ...

  4. IntelliJ IDEA下载地址

    http://www.jetbrains.org/display/IJOS/Download

  5. renren-fast-vue-动态路由

    在renren-fast-vue项目中,左侧边栏的系统管理这一模块的路由采用的是动态路由的写法, 模块中的路由内容由后台动态生成,在前端开发阶段,采用的是mock模拟数据生成 先是在左侧边栏(view ...

  6. NX二次开发-Block UI C++界面Toggle(开关)控件的获取(持续补充)

    NX9+VS2012 public: void SetBlockUIShow(); void ToggleInt::SetBlockUIShow() { //获取开关控件 //获取枚举控件 Prope ...

  7. TeleportPoint可瞬移的目标位置

    TeleportPoint.png 最外部的组件: Animation: 包含了该装置的几个动画Teleport Point: 点传送的脚本 teleport_marker_mesh: 外部的圆柱形光 ...

  8. 数据结构学习笔记——顺序数组2

    接着昨天的数组操作,数组初始化好了,我们要往里面添加元素,可以在尾部追加或者插入,刚开始数组为空,所以先追加 int AppendList(SqList* pArr, ElemType val) { ...

  9. (转)NAT与NAT穿越学习总结--ICE过程讲的不错

    转:http://cgs1999.iteye.com/blog/1994072 1.引言网络地址转换(Network Address Translation,简称NAT)是一种在IP分组通过路由器或防 ...

  10. (转)深刻理解Linux进程间通信(IPC)

    转:http://www.ibm.com/developerworks/cn/linux/l-ipc/index.html 序 linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来 ...