题意:
给定n支铅笔,问能不能分成若干堆,使得每堆数量不小于k且每堆的最大值和最小值之差不大于d。
题解:
排序。从后往前扫一遍,计算每个点能到达位置的后面位置是否为true。如果有一个为true则该点也为true。用树状数组来维护每个点能到达区间的合法位置和。
#include <bits/stdc++.h> using namespace std; int n, k, d; int a[500005], tre[500005]; int vis[500005]; void add(int x) { while(x <= n) { tre[x]++; x += x&(-x); } } int sum(int x) { int res = 0; while(x>0) { res += tre[x]; x -= x&(-x); } return res; } int main() { scanf("%d%d%d", &n, &k, &d); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a+1, a+n+1); for(int i = n-k+1; i >= 1; i--) { int l = i+k-1, r = upper_bound(a+i, a+n+1, a[i]+d)-a-1; if((r>=n) || (r>=l&&sum(r+1)-sum(l)>0)) vis[i] = 1; if(vis[i]) add(i); } if(vis[1]) puts("YES"); else puts("NO"); }