思路
考虑一次操作,假设最开始选择的数为 \(x\)。
那么这一轮对整个数组减去的数依次为 \(x,\lfloor\frac{x}{2}\rfloor,\lfloor\frac{x}{2^2}\rfloor,\cdots\)。
假设总共进行了 \(k\) 次操作,第 \(j\) 次选择的初始值为 \(x_j\)。
那么对于数组中的第 \(i\) 项,有 \(A_i=\sum_{j=1}^{k}\lfloor\frac{x_j}{2^{i-1}}\rfloor\)。
接下来考虑相邻的两项 \(A_{i-1}\) 和 \(A_i\)。
对于任意一个整数 \(x\),都有 \(\lfloor\frac{x}{2^{i-2}}\rfloor=2\lfloor\frac{x}{2^{i-1}}\rfloor\) 或 \(2\lfloor\frac{x}{2^{i-1}}\rfloor+1\)。
因此一次操作对 \(A_{i-1}-2A_i\) 的贡献只能是 \(0\) 或 \(1\)。
于是进行 \(k\) 次操作后,一定满足 \(0\le A_{i-1}-2A_i\le k\)。
所以首先必须有 \(A_{i-1}\ge 2A_i\)。
如果存在某个位置不满足这个条件,那么显然无解。
最少操作次数
如果满足上面的条件,对于每一个 \(i\),令 \(d_i=A_{i-1}-2A_i\)。
由于每次操作对 \(d_i\) 最多贡献 \(1\),所以至少需要 \(d_i\) 次操作。
因此答案至少为 \(\max d_i\)。
另一方面,可以把每个 \(d_i\) 理解为所有操作选择的 \(x\) 中,对应二进制位为 \(1\) 的数量。
不同二进制位可以独立决定,因此可以构造出这些 \(x\),使得每一个位置恰好有 \(d_i\) 个 \(1\)。
所以当数组不全为 \(0\) 时,最少操作次数就是 \(\max(1,\max_{i=2}^{n}(A_{i-1}-2A_i))\)。
这里还需要和 \(1\) 取最大值,因为只要数组中存在非零元素,就至少需要进行一次操作。
如果整个数组本来就全是 \(0\),答案显然为 \(0\)。
代码
#include <bits/stdc++.h>
#define rep(i,j,k) for (int i = (j); i <= (k); i ++)
#define per(i,j,k) for (int i = (j); i >= (k); i --)
#define uint unsigned int
#define ll long long
#define ull unsigned long long
#define db double
#define ldb long double
#define mkp make_pair
#define eb emplace_back
#define e_ emplace
#define ls (p << 1)
#define rs (p << 1 | 1)
//#define int ll
using namespace std;
const int N = 35;
//const int MOD = 998244353;
//const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LINF = 4e18;
int T;
int n, mx;
int a[N];
signed main () {
//freopen (".in", "r", stdin);
//freopen (".out", "w", stdout);
ios::sync_with_stdio (0);
cin.tie (0);
cin >> T;
while (T --) {
mx = 1;
cin >> n;
bool ck = true, em = true;
rep (i, 1, n) {
cin >> a[i];
if (a[i] != 0) em = false;
if (i != 1) {
if (a[i - 1] < a[i] * 2) ck = false;
mx = max (mx, a[i - 1] - a[i] * 2);
}
}
if (!ck) cout << -1 << '\n';
else if (em) cout << 0 << '\n';
else cout << mx << '\n';
}
return 0;
}
复杂度
每组数据只需要遍历一次数组。
时间复杂度为 \(O(N)\)。
如何想到
一开始可以先考虑一次操作对相邻两个位置的影响。假设这一轮在前一个位置减去 \(x\),那么后一个位置减去的是 \(\lfloor\frac{x}{2}\rfloor\)。
由于向下取整的性质,\(x\) 相对于 \(\lfloor\frac{x}{2}\rfloor\) 只可能有两种情况:
\(x=2\lfloor\frac{x}{2}\rfloor\) 或 \(x=2\lfloor\frac{x}{2}\rfloor+1\)。
也就是说,一次操作中,前一个位置减去的数一定是后一个位置减去的数的 \(2\) 倍或者 \(2\) 倍加 \(1\)。所以如果观察 \(A_{i-1}-2A_i\),一次操作只能让这个差值减少 \(0\) 或 \(1\)。
这样问题就变成了不断把这些差值缩小到 \(0\)。因此首先要求 \(A_{i-1}-2A_i\ge0\),否则无论如何都不可能消掉;而一个差值每次最多减少 \(1\),所以至少需要 \(A_{i-1}-2A_i\) 次操作。
于是自然想到答案与所有 \(A_{i-1}-2A_i\) 的最大值有关,最终得到 \(\max(1,\max(A_{i-1}-2A_i))\)。
浙公网安备 33010602011771号