CF 985E (ECR)

题意

对长度为\(N(1\leq N\leq5\times 10^5)\)的序列\(\{a_n\}(1\leq a_n \leq 10^9)\)进行分组,要求:

  • 每一个\(a_i\)必须属于且只能属于一个组
  • 每一个组内至少有\(K(K\leq N)\)个元素
  • 每个组内元素值的极差\(\max \{|a_i-a_j|\}\leq D,(1\leq D\leq 10^9)\)

试问满足条件的分组存不存在

分析

最有可能合法的分组是在有序序列上的分划

不妨假设序列存在单调性:\(a_i \leq a_{i+1}\),现在证明非连续的分组必定不比连续的分组优。分组

\[S_1=\{a_{s_1},...,a_{m-1},a_{m+1},...,a_{t_1}\}, S_2=\{a_{m},a_{s_2},...,a_{t_2}\},s_2=t_1+1$$与分组 $$S_1^*=\{a_{s_1},...,a_{t_1-1}\}, S_2^*=\{a_{t_1},a_{s_2},...,a_{t_2}\}$$相比,显然有$$\#S_1=\#S_1^*$$且$$ \#S_2=\#S_2^*$$另外$$|a_{t_1}-a_{s_1}|+|a_{t_2}-a_m|\geq|a_{t_1-1}-a_{s_1}|+|a_{t_2}-a_{t_1}|$$故在分组大小相同的情况下,由于三角不等式,连续的分划更有可能是合法分组,下面我们讨论如何分划最优 ##枚举分划的右端点,查找合法的左端点 令$dp[i]=1$表示$a_i$与$a_{i-1}$之间的分划是合法的,即$\{a_n\},n\leq i-1$的合法分组存在。 反过来$dp[i]=0$表示$a_i$与$a_{i-1}$之间的分划不合法,即$\{a_n\},n\leq i-1$的合法分组不存在。 另外,记$s[n]=\sum_{i=1}^n {dp[i]}$,即$dp$序列的前缀和序列。 ###边界条件 $dp[0]=s[0]=1$ ###转移方程 要求$dp[n]$,就必须知道其对应的合法左端点在什么位置,由于$K$限制,不能太靠右,由于$D$限制,不能太靠左,而在某一个区间$[l,r]$内的合法左端点都是可以继承的。 由于我们的分组是连续的,$K$限制下的$r=n-K$ 又由于我们的序列是单调的,$D$限制下的$l$可以使用二分查找法找到 任务变成了在$dp[l],...,dp[r]$之间,是否有$1$的存在,即$s[r]-s[l-1]$是否为$0$,即可 $$dp[n]=!!(s[r]-s[l-1])$$ $$s[n]=s[n-1]+dp[n]$$ 最后答案取决于$dp[N+1]$的值是否为$1$ ###复杂度 $O(n\log n)$ #代码 ```c++ /* Yuanjie Duane Ding (c) 2017 * any codes cannot be used for business * BUAA开学季 * Templates for Codeforces special */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define NAME "985E" using namespace std; int N, K, D; int av[500005], sn[500005]; void readin() { scanf("%d%d%d", &N, &K, &D); for(int i = 1; i <= N; ++i) { scanf("%d", av+i); } } void process() { sort(av+1, av+1+N); sn[1] = 1; int l, r, tot; for(int i = 1; i <= N; ++i) { r = i-K+1; l = lower_bound(av+1, av+1+N, av[i]-D)-av; if(r < 1 || r < l || r > i) { sn[i+1] = sn[i]; continue; } tot = sn[r]-sn[l-1]; sn[i+1] = sn[i]+(bool)tot; #ifdef DEBUG printf("%d: [%d, %d], tot %d\n", i, l, r, tot); #endif } #ifdef DEBUG for(int i = 1; i <= N+1; ++i) { printf("%d: av %d; sn %d; val %d\n", i, av[i], sn[i], sn[i]-sn[i-1]); } #endif if(sn[N+1] > sn[N]) { cout << "YES" << endl; } else { cout << "NO" << endl; } } int main() { #ifndef ONLINE_JUDGE freopen(NAME ".in", "r", stdin); #endif readin(); process(); return 0; } ```\]

posted on 2018-05-23 21:57  No_CE_in_Vegetable  阅读(776)  评论(0编辑  收藏  举报

导航