题解:Codeforces Round 961 (Div. 2) C

C. Squaring

time limit per test: 2 seconds

memory limit per test: 256 megabytes

input: standard input

output: standard output

ikrpprpp found an array a a a consisting of integers. He likes justice, so he wants to make a a a fair — that is, make it non-decreasing. To do that, he can perform an act of justice on an index 1 ≤ i ≤ n 1 \le i \le n 1in of the array, which will replace a i a_i ai with a i 2 a_i ^ 2 ai2 (the element at position i i i with its square). For example, if a = [ 2 , 4 , 3 , 3 , 5 , 3 ] a = [2,4,3,3,5,3] a=[2,4,3,3,5,3] and ikrpprpp chooses to perform an act of justice on i = 4 i = 4 i=4, a a a becomes [ 2 , 4 , 3 , 9 , 5 , 3 ] [2,4,3,9,5,3] [2,4,3,9,5,3].

What is the minimum number of acts of justice needed to make the array non-decreasing?

ikrpprpp 发现了一个由整数组成的数组 a a a 。他喜欢公平,所以想让 a a a 变得公平,也就是让它不递减。为此,他可以对数组中的索引 1 ≤ i ≤ n 1 \le i \le n 1in 进行公正操作,将 a i a_i ai 替换为 a i 2 a_i ^ 2 ai2 (位置 i i i 的元素及其平方)。例如,如果 a = [ 2 , 4 , 3 , 3 , 5 , 3 ] a = [2,4,3,3,5,3] a=[2,4,3,3,5,3] 和ikrpprpp选择在 i = 4 i = 4 i=4 上执行正义行动,那么 a a a 就会变成 [ 2 , 4 , 3 , 9 , 5 , 3 ] [2,4,3,9,5,3] [2,4,3,9,5,3]

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

Input

First line contains an integer t t t ( 1 ≤ t ≤ 1000 1 \le t \le 1000 1t1000) — the number of test cases. It is followed by the description of test cases.

For each test case, the first line contains an integer n n n — size of the array a a a. The second line contains n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10 ^5 1n2105) integers a 1 , a 2 , … , a n a_1, a_2,\ldots, a_n a1,a2,,an ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10 ^ 6 1ai106).

The sum of n n n over all test cases does not exceed 2 ⋅ 10 5 2 \cdot {10}^5 2105.

输入

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

对于每个测试用例,第一行包含一个整数 n n n - 数组的大小 a a a 。第二行包含 n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10 ^5 1n2105 ) 个整数 a 1 , a 2 , … , a n a_1, a_2,\ldots, a_n a1,a2,,an ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10 ^ 6 1ai106 )。

所有测试用例中 n n n 的总和不超过 2 ⋅ 10 5 2 \cdot {10}^5 2105

Output

For each testcase, print an integer — minimum number of acts of justice required to make the array a a a non-decreasing. If it is impossible to do that, print − 1 -1 1.

输出

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

Example
input

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

output

0
1
-1
0
3
15
55

Note

In the first test case, there’s no need to perform acts of justice. The array is fair on its own!

In the third test case, it can be proven that the array cannot become non-decreasing.

In the fifth test case, ikrpprppp can perform an act of justice on index 3, then an act of justice on index 2, and finally yet another act of justice on index 3. After that, a a a will become [ 4 , 9 , 16 ] [4, 9, 16] [4,9,16].

题意
对每个数可以选择平方或者不平方,可以操作无数次
使得这个数列不递减

我的题解
因为题目给的数据范围很大
如果平方暴力会爆long long
如果开方会丢失精度
所以我们要标记去记录某个数平方了多少次

从第二个数到最后一个数递推(因为第一个数不用动)
首先比较原数字,有两种情况(假设 a a a b b b 前面)

  • a > b a \gt b a>b
    • 那我们就是需要让 b b b 不断变成 b 2 b^2 b2 直到 b ≥ a b \ge a ba (但是要先把b复制出来,让复制体去平方,不要改变 b b b 本身,因为 b b b 可能还要和后面的数字比较),记录平方的次数,加上 a a a 的平方的次数,就是 b b b 真正的平方次数。
  • a ≤ b a \le b ab
    • 虽然理论上我们不需要比较,但是因为 a a a 实际上可能已经平方过,我们去算真正的 a a a 又可能会爆long long,所以我们不能暴力
    • 我们可以计算 a a a 需要平方多少次才能实现 a ≥ b a \ge b ab,然后 b b b 实际上需要平方的次数就是 a a a 实际上平方的次数减去这个数;如果这个数小于 0 0 0,那就只能取 0 0 0

最后,我们对这些平方次数求和,就是答案了。

我的代码

#include <bits/stdc++.h>
#define int long long

int t,n;
const int N = 2e5 + 1;
int a[N];
int ans[N];
int mem,cnt;

void solve() {
    std::cin >> n;
    for(int i = 0 ; i < n ; i ++) std::cin >> a[i];
    for(int i = 1 ; i < n ; i ++) {
        mem = a[i];
        cnt = 0;
        if(mem < a[i-1]) {
            if(mem == 1) {
                std::cout << -1 << "\n";
                return;
            }
            while(mem < a[i-1]) {
                mem *= mem;
                cnt ++;
            }
        }
        else if(a[i-1] != 1){
            while(mem >= a[i-1]) {
                a[i-1] *= a[i-1];
                cnt --;
            }
            if(a[i-1] != mem) cnt ++;
        }

        ans[i] = std::max(cnt + ans[i-1],(int)0);
    }

    int m = 0;
    for(int i = 0 ; i < n ; i ++) {
        m += ans[i];
    }
    std::cout << m << "\n";
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::cin >> t;
    while(t--) solve();
    return 0;
}

转载自博客https://www.cnblogs.com/jiejiejiang2004/p/18324353
博主已同意,我就是博主

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值