Codeforces Round 878 (Div. 3) C. Ski Resort

发布时间 2023-10-18 21:54:43作者: zsxuan

你有连续的 \(n\) 天假期,第 \(i\) 天的温度为 \(a_i\) 。你计划在这 \(n\) 天中选择连续的若干天去旅游,至少为 \(k\) 天。给定一个 \(q\) ,你需要确保你出去旅游的时间中每天的温度都 \(\leq q\) 。询问你有多少种计划旅游的方案。

不难用双指针找出所有连续子段 \([l, r]\) 满足 \(max_{i = l}^{n} a_i \leq q\) 。设某一段长度为 \(len\) ,当 \(len \geq k\)

  • \(k\) 天的方案数为 \(len - k + 1\)
  • \(k + 1\) 天的方案数为 \(len - k + 2\)
  • \(len\) 天的方案数位 \(1\)

归纳出长度为 \(len\ (len \geq k)\) 的段贡献为 \(\frac{(len - k + 1)(len - k + 2)}{2}\)

view
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
void solve(){
	int n, k, q; std::cin >> n >> k >> q;
	std::vector<int> a(n+1);
	for (int i = 1; i <= n; i++) std::cin >> a[i];
	ll ans = 0;
	for (int i = 1; i <= n; i++) {
		int j = i;
		if (a[j] > q) continue; // 双指针的这一步很关键,需要保证 j 是非法第一位,不产生回退
		while (j <= n && a[j] <= q) j++;
		j -= 1;
		int seg = j - i + 1;
		if (seg >= k) ans += 1LL * (seg - k + 1) * (seg - k + 2) / 2;
		i = j;
	}
	std::cout << ans << '\n';
}
		                
int main() {
	#ifndef ONLINE_JUDGE
    freopen("IO/in", "r", stdin); freopen("IO/out", "w", stdout);
	#endif 
	int _ = 1; std::cin >> _;
	while (_--) solve();
	return 0;
}