ABC388G Simultaneous Kagamimochi 2

问题描述

\(N\) 个元团子(米团),按照大小升序排列。第 \(i\) 个元团子 \((1≤i≤N)\) 的大小是 \(A_i\)

给定两个元团子 \(A\)\(B\),它们的大小分别是 \(a\)\(b\) ,你只有在 \(a\) 不超过 \(b\) 的一半时,才能通过将元团子 \(A\) 放在元团子\(B\)之上来制作一个元团子(kagamimochi)。

你被给予Q对整数。设 \((L_i, R_i)\) 是第 \(i\)\((1≤i≤Q)\),对于每个 \(i\),解决以下问题:

仅使用从第 \(L_i\) 个到第 \(R_i\) 个的 \(R_i-L_i+1\) 个元团子,你能同时制作多少个元团子?

更具体地说,找出最大非负整数 \(K\),使得:

  • 在从第\(L_i\)个到第\(R_i\)个的\(R_i - L_i + 1\)个元团子中,选择 \(2K\) 个元团子并形成 \(K\) 对。对于每对元团子,将一个放在另一个之上,以制造 \(K\) 个元团子(kagamimochi)。

题解

设答案为 \(k\),那么可以知道,在区间中最小 \(k\) 个和最大 \(k\) 个可以相互组合起来。设区间区间开头为 \(l\),末尾为 \(r\),那么可以这么组合 \((l, r - k + 1),(l + 1, r - k + 2),...,(l+i - 1,r-k+i)\)

我们尝试在 \([0,\frac{r - l + 1}{2}]\) 二分答案,二分 \(k\),设 \(N_i\)\(i\) 可以在 \([N_i, n]\) 里面的数组合。

\(i\in[l, l + k - 1]\),我们要求 \(i\)\(r - l + 1 - k + i\),那么可以得出 \(N_i\le r - l + 1 - k + i\) 移项得 \(N_i - i\le r - l + 1 - k\),用 ST 维护一下就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::cin, std::cout;

#define lF(i, a, b) for (int i = a, END##i = b; i <= END##i; i++)
#define rF(i, a, b) for (int i = a, END##i = b; i >= END##i; i--)

void Init();
void Solve();

signed main() {
	cin.sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		Init();
		Solve();
	}
	return 0;
}

using LL = long long;
using ULL = unsigned long long;

const int Mod = 1e9 + 7;
const int Inf = 0x3f3f3f3f;
const LL InfLL = 0x3f3f3f3f3f3f3f3f;

const int N = 2e5 + 10, M = 30;
int n, a[N], Log[N], Ne[N], f[N][M];
int l, r;

void init_ST() {
	lF(i, 2, n) Log[i] = Log[i >> 1] + 1;
	lF(i, 1, n) f[i][0] = Ne[i] - i;
	for (int j = 1; (1 << j) <= n; j++)
		lF(i, 1, n - (1 << j) + 1)
			f[i][j] = std::max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
int ask(int L, int R) {
	int k = Log[R - L + 1];
	return std::max(f[L][k], f[R - (1 << k) + 1][k]);
}

bool check(int Mid) {
	int x = ask(l, l + Mid - 1);
	return l + Mid - 1 + x <= r;
}

void Init() {
}

void Solve() {
	cin >> n;
	lF(i, 1, n) cin >> a[i];
	lF(i, 1, n) Ne[i] = std::lower_bound(a + 1, a + n + 1, 2 * a[i]) - a;
	init_ST();
	int Q; cin >> Q;
	while (Q--) {
		cin >> l >> r;
		int L = 0, R = r - l + 1 >> 1;
		while (L < R) {
			int Mid = L + R + 1 >> 1;
			if (check(Mid)) L = Mid;
			else R = Mid - 1;
		}
		cout << L << "\n";
	}
}
posted @ 2025-01-22 16:36  wh2011  阅读(40)  评论(0)    收藏  举报