cf487 B. Strip
题意:
把数组切成若干段,每段长度不小于len,每段内极差不大于z。问最少切成几段。
思路:
\(f(i)\) 表示 \(1\sim i\) 最少能切成(合法的)几段,-1表示没有合法方案。
则 \(f(i)=\min \{ f(j):j<i,[j+1,i]的极差\le z,f(j)\neq -1 \}+1\)
显然 \(f(i)\) (除了-1外)关于 \(i\) 递增,所以只需用指针 p 维护最左即最小的 \(j\)
怎么维护区间极差呢?可以RMQ、线段树、multiset、两个堆等,RMQ的预处理也要nlogn,所以直接用最简单的multiset好了
const signed N = 1e5 + 3;
int n, z, len, a[N], f[N];
multiset<int> S;
signed main() {
iofast;
cin >> n >> z >> len;
for(int i = 1; i <= n; i++) cin >> a[i];
memset(f, -1, sizeof f), f[0] = 0;
for(int i = 1, p = 0; i <= n; i++) {
S.insert(a[i]);
while(p < i && (*S.rbegin() - *S.begin() > z || f[p] == -1))
S.erase(S.find(a[++p]));
if(i - p >= len && f[p] != -1) f[i] = f[p] + 1;
}
cout << f[n];
}

浙公网安备 33010602011771号