Squaring

题目链接:

Problem - C - Codeforces


题目描述

ikrpprpp 发现了一个由整数组成的数组 aa 。他喜欢公平,所以想让 aa 变得公平,也就是让它不递减

为此,他可以对数组中的索引 1in1≤i≤n 进行公正操作,将 aia_i 替换为 ai2a_i^2 (位置 ii 的元素及其平方)。例如,如果 a=[2,4,3,3,5,3]a=[2,4,3,3,5,3] ,ikrpprpp 选择对 i=4i=4 执行正义行动,那么 aa 就会变成 [2,4,3,9,5,3][2,4,3,9,5,3]

要使数组不递减,最少需要多少次正义行动?

输入格式

第一行包含一个整数 t ( 1t1000 )t ( 1≤t≤1000 ) - 测试用例的数量。随后是测试用例的描述。

对于每个测试用例,第一行包含一个整数 nn - 数组 aa 的大小。第二行包含 n ( 1n2105 )n ( 1≤n≤2*10^5 ) 个整数 a1,a2,,an1ai106a1,a2,…,an(1≤a_i≤10^6)

所有测试用例中 nn 的总和不超过 21052*10^5 。

输出格式

对于每个测试用例,打印一个整数–使数组 aa 不递减所需的最小正义行为数。如果无法做到,则打印1−1

样例 #1

样例输入 #1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7
3
1 2 3
2
3 2
3
3 1 5
4
1 1 2 3
3
4 3 2
9
16 2 4 2 256 2 4 2 8
11
10010 10009 10008 10007 10006 10005 10004 10003 10002 10001 10000

样例输出 #1

1
2
3
4
5
6
7
0
1
-1
0
3
15
55

注释

在第一个测试案例中,无需执行正义行为。阵列本身就是公平的!

在第三个测试案例中,可以证明数组不可能非递减。

在第五个测试用例中,ikrpprppp 可以在索引 33 上执行一次正义行动,然后在索引 22 上执行一次正义行动,最后在索引 33 上执行另一次正义行动。之后, aa 将变成 [4,9,16][4,9,16] 。


题解

观察数据范围,我们可以暴力求解次数。但是这样会面临一个问题,爆long long而导致答案错误。

我们先来观察相邻的两个数。我们假定 a,ba,b 是两个相邻的数,如果 a>ba>b,我们需要对 bb 操作。假设 aa 是数组的第一个元素,我们只需要找到一个 nn ,使得 bn1<abnb^{n-1}<a≤b^n 。那么如果 aa 并不是数组的第一个元素呢,我们假设到 aa 时要满足条件需要 aa 进行了 mm 次操作,即 ama^m,此时,由于幂函数的单调性可知 b(n1)+m<ambn+mb^{(n-1)+m}<a^m≤b^{n+m} 依然成立。也就是说到 a,ba,b 时,bb 需要操作 m+nm+n 次。

所以,我们只需要遍历数组,记录下前 i1i-1 个数时的操作次数,即可得到第 ii 个数的操作次数,然后累加即可。

下面是 ac 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;

ll a[200005] = {0};
ll b[200005] = {0};

void debug()
{
return;
}

void solve()
{
int n;
cin >> n;
ll mymin = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 2; i <= n; i++)
{
if (a[i] == 1 && a[i - 1] != 1)
{
cout << -1 << endl;
return;
}
else
{
ll p = a[i - 1];
ll now = a[i];
ll extra = 0;
while (p * p <= now)
{
extra -= 1, p *= p;
}
while (now < p)
{
extra++, now *= now;
}

b[i] = max(0ll, b[i - 1] + extra);
}
}
ll ans = 0;
for (int i = 2; i <= n; i++)
{
ans += b[i];
}
cout << ans << endl;
return;
}

int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);

int t;
t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}

Squaring
https://serendipity565.github.io/posts/28859ead9ebc/
作者
Serendipity
发布于
2024年7月24日
许可协议
BY-SERENDIPITY565