问题描述
有 \(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";
}
}
标签:lF,const,int,cin,ABC388G,Simultaneous,团子,Kagamimochi,个元
From: https://www.cnblogs.com/wh2011/p/18686211