给一个长度为 \(n\) 的序列 \(a\) 。c++
对于第 \(i\) 秒,咱们能够选择若干个位置上的数加上 \(2^{i-1}\) 。spa
问最少在第几秒的时候,能够使得 \(a_1 \leq a_2\leq...\leq a_n\) 。code
首先不难注意到,对于前 \(i\) 秒,咱们能够使得一个数加上 \(x\in[1,2^i-1]\)。ip
也就是说对于前 \(i\) 秒,咱们能够让一个数 \(x\) 变成 \([x,x+2^i-1]\) 内的任意一个数。get
考虑一下这个式子 \(a_1 \leq a_2\leq...\leq a_n\) ,显然,\(a_i\) 越小,则 \(a_{i+1}\) 至 \(a_n\) 越有 " 操做空间 " 。string
又由于操做只会致使数变大,因此咱们显然是不要去动这个 \(a_1\) 。it
接着考虑一下 \(a_2\) :io
以此类推,咱们接着考虑 \(a_3,a_4,...,a_n\) ,假设咱们如今考虑到第 \(i\) 位:class
这样考虑完这 \(n\) 位便可求出答案,\(\mathcal{O(n \log \log size)}\),其中 \(size\) 表示的是值域大小。gc
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; namespace IO { static char buf[1 << 20], *fs, *ft; inline char gc() { if (fs == ft) { ft = (fs = buf) + fread(buf, 1, 1 << 20, stdin); if (fs == ft) return EOF; } return *fs ++; } #define gc() getchar() inline int read() { int x = 0, f = 1; char s = gc(); while (s < '0' || s > '9') {if (s == '-') f = -f; s = gc();} while (s >= '0' && s <= '9') {x = x * 10 + s - '0'; s = gc();} return x * f; } } using IO :: read; const int N = 200100; int n; long long a[N]; void work() { n = read(); for (int i = 1; i <= n; i ++) a[i] = read(); int ans = 0; for (int i = 2; i <= n; i ++) { if (a[i - 1] <= a[i]) continue; int l = 1, r = 33; while (l < r) { int mid = (l + r) / 2; long long delta = (1ll << mid) - 1; if (a[i - 1] <= a[i] + delta) r = mid; else l = mid + 1; } ans = max(ans, l); a[i] = a[i - 1]; } printf("%d\n", ans); } int main() { int T = read(); while (T --) work(); return 0; }