codeforces 985 E. Pencils and Boxes (dp 树状数组)
2 seconds
256 megabytes
standard input
standard output
Mishka received a gift of multicolored pencils for his birthday! Unfortunately he lives in a monochrome world, where everything is of the same color and only saturation differs. This pack can be represented as a sequence a1, a2, ..., an of n integer numbers — saturation of the color of each pencil. Now Mishka wants to put all the mess in the pack in order. He has an infinite number of empty boxes to do this. He would like to fill some boxes in such a way that:
- Each pencil belongs to exactly one box;
- Each non-empty box has at least k pencils in it;
- If pencils i and j belong to the same box, then |ai - aj| ≤ d, where |x| means absolute value of x. Note that the opposite is optional, there can be pencils i and j such that |ai - aj| ≤ d and they belong to different boxes.
Help Mishka to determine if it's possible to distribute all the pencils into boxes. Print "YES" if there exists such a distribution. Otherwise print "NO".
The first line contains three integer numbers n, k and d (1 ≤ k ≤ n ≤ 5·105, 0 ≤ d ≤ 109) — the number of pencils, minimal size of any non-empty box and maximal difference in saturation between any pair of pencils in the same box, respectively.
The second line contains n integer numbers a1, a2, ..., an (1 ≤ ai ≤ 109) — saturation of color of each pencil.
Print "YES" if it's possible to distribute all the pencils into boxes and satisfy all the conditions. Otherwise print "NO".
6 3 10
7 2 7 7 4 2
YES
6 2 3
4 5 3 13 4 10
YES
3 2 5
10 16 22
NO
In the first example it is possible to distribute pencils into 2 boxes with 3 pencils in each with any distribution. And you also can put all the pencils into the same box, difference of any pair in it won't exceed 10.
In the second example you can split pencils of saturations [4, 5, 3, 4] into 2 boxes of size 2 and put the remaining ones into another box.
【题意】
给$$$n$$$个数,可以放到若干个盒子里,要求每个盒子至少有$$$k$$$个数,并且每个盒子中最大和最小的数差值不超过$$$d$$$。问是否有合理的方案来分配。
【分析】
因为要比较差值,所以按从小到大对输入排序,如果$$$a_i$$$和$$$a_j$$$已经放到同一个盒子里了,那么大小介于$$$a_i$$$和$$$a_j$$$之间的数也一定可以放到这个盒子中。
由于上述的性质,每个盒子都应该装$$$a_i$$$~$$$a_j$$$的全部数。因为$$$a_i$$$和$$$a_j$$$是离其他数最近的数,如果现在的分配不可行,一定是先把$$$a_i$$$或$$$a_j$$$重新划分给相邻的盒子,成为新的区间端点,而整个方案依然的连续的;而如果$$$a_i$$$和$$$a_j$$$不能分配给其他盒子,那么内部的其他数也一定不行。从另一方面来说,如果把一个$$$a_i$$$~$$$a_j$$$中的一个$$$a_x$$$拿出去,最终形成了可行方案,那么一定可以通过把$$$a_x$$$与$$$a_i$$$或$$$a_j$$$交换,使方案依然可行而且每个盒子中变成连续的区间。
连续分配说明完了,之后都把盒子当作区间来处理,问题转化为:把1~n个数分为几个连续的区间,使的每个区间$$$[a_i, a_j]$$$的$$$a_j-a_i \le d, j-i \ge k$$$。
预处理:对于每个$$$a_i$$$一定有一个最大的$$$a_j$$$,用二分查找得到其下标,并把$$$a_j$$$下一个位置也就是$$$j+1$$$记录到$$$right[i]$$$ (下面会介绍) 中。
如果一个盒子是$$$[a_i, a_j]$$$那么下一个盒子的起点就是$$$a_{j+1}$$$。可以把从$$$a_i$$$到$$$a_{j+1}$$$看成一次转移,这样重复下去,如果最后刚好能到达数列的末端,那么从$$$a_i$$$开始就是可行的,$$$a_i$$$就是能到末端的点。这个时候$$$right[i]$$$数组就发挥作用了,对于$$$a_i$$$,它能转移到的起点有 $$$a_{i+k}, a_{i+k+1}, ...,a_{right[i]}$$$;
dp可以采取从后向前的顺序。在考虑$$$a_i$$$作为起点时,它可以转移到的点都在它后面,所以$$$[a_{i+k}, a_{right[i]}]$$$都处理过了,只要其中包含末端,或者能到末端的点,那么$$$a_i$$$也是能到达末端的点;如果区间不存在,或者不包含能到末端的点,那么$$$a_i$$$就不能到达末端。这样从后向前处理完所有点以后,起点能否到达末端就是答案的YES/NO。
如果用0表示无法到达末端,1表示能到达末端,那么转移方程就是:
$$$$$$dp[i]= (\sum_{j=i+k}^{right[i]} dp[j]) \gt 0$$$$$$
起始状态为$$$dp[n]$$$=$$$1$$$。
【注意】
使用树状数组来完成求和操作,下标的起点必须是1。
#include<stdio.h>
#include<algorithm>
using std::sort; #define N_max 500005
int ipt[N_max], right[N_max]; int n, k, d;
int cmpv(int t1, int t2) {
return t1 < t2;
}
void cal_r(int i) {
if (right[i] != 0)return;
int l = i, r = n + 1, m;
while (l + 1<r)
{
m = (l + r) / 2;
if (ipt[m] <= ipt[i] + d)l = m;
else r = m;
}
right[i] = r;
}
struct BIT {
int c[N_max] = { 0 };//每个ci维护的都是1~i的最新和
int lowbit[N_max] = { 0 };
int n;
BIT(int _n = N_max) {
n = _n;
for (int i = 1; i <= N_max; ++i) lowbit[i] = (i&(-i));
}
void newBIT(int _n) {
n = _n;
for (int i = 1; i <= n; ++i)
c[i] = 0;
}
//更新时向右(上)更新
void update(int x, int num) {
while (x <= n) {
c[x] += num;
x += lowbit[x];
}
}
//求和时向左(下)依次求和
int getsum(int x) {
int s = 0;
while (x > 0) {
s += c[x];
x -= lowbit[x];
}
return s;
}
}bit;
int main() {
scanf("%d %d %d", &n, &k, &d);
bit.newBIT(n+1);
for (int i = 1; i <= n; ++i)
scanf("%d", ipt + i); sort(ipt + 1, ipt + n + 1, cmpv);
int state;
//初始状态为只有末端可以到达末端
bit.update(n + 1, 1);
//计算right[i]
for (int i = 1; i <= n; ++i)
cal_r(i);
//从后向前dp
for (int i = n; i >= 1; --i)
{
if (i + k - 1 <= n)//至少存在一个
{
//使用树状数组判断区间内是否有不为0 的值
state = (bit.getsum(right[i]) - bit.getsum(i + k - 1)) > 0;
bit.update(i, state);
}
}
state = bit.getsum(1);
printf("%s", state == 1 ? "YES" : "NO");
return 0;
}
codeforces 985 E. Pencils and Boxes (dp 树状数组)的更多相关文章
- 树形DP+树状数组 HDU 5877 Weak Pair
//树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...
- bzoj 1264 [AHOI2006]基因匹配Match(DP+树状数组)
1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 793 Solved: 503[Submit][S ...
- 【bzoj2274】[Usaco2011 Feb]Generic Cow Protests dp+树状数组
题目描述 Farmer John's N (1 <= N <= 100,000) cows are lined up in a row andnumbered 1..N. The cows ...
- 奶牛抗议 DP 树状数组
奶牛抗议 DP 树状数组 USACO的题太猛了 容易想到\(DP\),设\(f[i]\)表示为在第\(i\)位时方案数,转移方程: \[ f[i]=\sum f[j]\;(j< i,sum[i] ...
- CodeForces - 597C Subsequences 【DP + 树状数组】
题目链接 http://codeforces.com/problemset/problem/597/C 题意 给出一个n 一个 k 求 n 个数中 长度为k的上升子序列 有多少个 思路 刚开始就是想用 ...
- codeforces 597C C. Subsequences(dp+树状数组)
题目链接: C. Subsequences time limit per test 1 second memory limit per test 256 megabytes input standar ...
- Codeforces 1096F(dp + 树状数组)
题目链接 题意: 对于长度为$n$的排列,在已知一些位的前提下求逆序对的期望 思路: 将答案分为$3$部分 $1.$$-1$与$-1$之间对答案的贡献.由于逆序对考虑的是数字之间的大小关系,故假设$- ...
- Codeforces 909 C. Python Indentation (DP+树状数组优化)
题目链接:Python Indentation 题意: Python是没有大括号来标明语句块的,而是用严格的缩进来体现.现在有一种简化版的Python,只有两种语句: (1)'s'语句:Simple ...
- Codeforces 1085G(1086E) Beautiful Matrix $dp$+树状数组
题意 定义一个\(n*n\)的矩阵是\(beautiful\)的,需要满足以下三个条件: 1.每一行是一个排列. 2.上下相邻的两个元素的值不同. 再定义两个矩阵的字典序大的矩阵大(从左往右从上到下一 ...
随机推荐
- 1030: [JSOI2007]文本生成器
1030: [JSOI2007]文本生成器 https://www.lydsy.com/JudgeOnline/problem.php?id=1030 分析: AC自动机+dp. 正难则反,求满足的, ...
- 4946: [Noi2017]蔬菜
4946: [Noi2017]蔬菜 http://www.lydsy.com/JudgeOnline/upload/Noi2017D2.pdf 分析: 贪心. 首先可以将一个蔬菜拆成两个,一个是有加成 ...
- 10、Java并发编程:并发容器之ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- MySQL高级-锁机制
一.概述 1.定义 2.锁的分类 ①从对数据操作的类型(读\写)分 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响. 写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁 ...
- join_tab计算代价
此路不通,还是需要按照顺序进行计算
- adb获取设备的序列号
用数据线连接手机, 打开开发者模式, 并赋予相关权限, 在CMD命令行输入: adb devices 第一个参数即为设备的序列号, 第二个参数device表示设备的状态是在线.
- <cerrno>
文件头名称: <cerrno>(errno.h) 文件头描述: 文件内定义了如下的宏 errno 最后一个错误代码 加上其他至少的三个宏常量:EDOM,ERANGE 和EILSEQ 宏定 ...
- Siki_Unity_1-9_Unity2D游戏开发_Roguelike拾荒者
Unity 1-9 Unity2D游戏开发 Roguelike拾荒者 任务1:游戏介绍 Food:相当于血量:每走一步下降1,吃东西可以回复(果子10药水20),被怪物攻击会减少中间的障碍物可以打破, ...
- php导出excel表格的使用
网站后台有很多列表数据,常常都会有导出excel表格的需求,和大家分享一个实用的导出excel表格方法: 不多说,上代码: /** * @param array $data 要导出的数据 * @par ...
- vue中如何实现pdf文件预览?
今天产品提出一个优化的需求,就是之前我们做的图片展示就是一个img标签搞定,由于我们做的是海外后台管理系统,那边的人上传的文件时pdf格式,vue本事是不支持这种格式文件展示的,于是就google搜索 ...