Codeforces Round 949 (Div. 2) C. Turtle and an Incomplete Sequence 题解 构造

Turtle and an Incomplete Sequence

题目描述

Turtle was playing with a sequence a 1 , a 2 , ... , a n a_1, a_2, \ldots, a_n a1,a2,...,an consisting of positive integers. Unfortunately, some of the integers went missing while playing.

Now the sequence becomes incomplete. There may exist an arbitrary number of indices i i i such that a i a_i ai becomes − 1 -1 −1. Let the new sequence be a ′ a' a′.

Turtle is sad. But Turtle remembers that for every integer i i i from 1 1 1 to n − 1 n - 1 n−1, either a i = ⌊ a i + 1 2 ⌋ a_i = \left\lfloor\frac{a_{i + 1}}{2}\right\rfloor ai=⌊2ai+1⌋ or a i + 1 = ⌊ a i 2 ⌋ a_{i + 1} = \left\lfloor\frac{a_i}{2}\right\rfloor ai+1=⌊2ai⌋ holds for the original sequence a a a.

Turtle wants you to help him complete the sequence. But sometimes Turtle makes mistakes, so you need to tell him if you can't complete the sequence.

Formally, you need to find another sequence b 1 , b 2 , ... , b n b_1, b_2, \ldots, b_n b1,b2,...,bn consisting of positive integers such that:

  • For every integer i i i from 1 1 1 to n n n, if a i ′ ≠ − 1 a'_i \ne -1 ai′=−1, then b i = a i ′ b_i = a'_i bi=ai′.
  • For every integer i i i from 1 1 1 to n − 1 n - 1 n−1, either b i = ⌊ b i + 1 2 ⌋ b_i = \left\lfloor\frac{b_{i + 1}}{2}\right\rfloor bi=⌊2bi+1⌋ or b i + 1 = ⌊ b i 2 ⌋ b_{i + 1} = \left\lfloor\frac{b_i}{2}\right\rfloor bi+1=⌊2bi⌋ holds.
  • For every integer i i i from 1 1 1 to n n n, 1 ≤ b i ≤ 1 0 9 1 \le b_i \le 10^9 1≤bi≤109.

If there is no sequence b 1 , b 2 , ... , b n b_1, b_2, \ldots, b_n b1,b2,...,bn that satisfies all of the conditions above, you need to report − 1 -1 −1.

输入描述

Each test contains multiple test cases. The first line contains the number of test cases t t t ( 1 ≤ t ≤ 1 0 5 1 \le t \le 10^5 1≤t≤105). The description of the test cases follows.

The first line of each test case contains a single integer n n n ( 2 ≤ n ≤ 2 ⋅ 1 0 5 2 \le n \le 2 \cdot 10^5 2≤n≤2⋅105) --- the length of the sequence.

The second line of each test case contains n n n integers a 1 ′ , a 2 ′ , ... , a n ′ a'_1, a'_2, \ldots, a'_n a1′,a2′,...,an′ ( a i ′ = − 1 a'_i = -1 ai′=−1 or 1 ≤ a i ′ ≤ 1 0 8 1 \le a'_i \le 10^8 1≤ai′≤108) --- the elements of the sequence a ′ a' a′.

It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105.

输出描述

For each test case, if there is no sequence b 1 , b 2 , ... , b n b_1, b_2, \ldots, b_n b1,b2,...,bn that satisfies all of the conditions, output a single integer − 1 -1 −1.

Otherwise, output n n n integers b 1 , b 2 , ... , b n b_1, b_2, \ldots, b_n b1,b2,...,bn --- the elements of the sequence b 1 , b 2 , ... , b n b_1, b_2, \ldots, b_n b1,b2,...,bn you find. The sequence should satisfy that 1 ≤ b i ≤ 1 0 9 1 \le b_i \le 10^9 1≤bi≤109 for every integer i i i from 1 1 1 to n n n. If there are multiple answers, print any of them.

样例 #1

样例输入 #1

复制代码
9
8
-1 -1 -1 2 -1 -1 1 -1
4
-1 -1 -1 -1
6
3 -1 -1 -1 9 -1
4
-1 5 -1 6
4
2 -1 -1 3
4
1 2 3 4
2
4 2
5
-1 3 -1 3 6
13
-1 -1 3 -1 -1 -1 -1 7 -1 -1 3 -1 -1

样例输出 #1

复制代码
4 9 4 2 4 2 1 2
7 3 6 13
3 1 2 4 9 18
-1
-1
-1
4 2
6 3 1 3 6
3 1 3 1 3 7 3 7 3 1 3 1 3

原题

CF------传送门

思路&代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
typedef long long ll;

void solve()
{
    int n;
    cin >> n;
    vector<int> a(n);
    vector<int> idx;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (a[i] != -1)
            idx.push_back(i); // idx数组保存所有值非-1的下标
    }
    if (idx.empty()) // 特判全是-1的情况
    {
        for (int i = 0; i < n; i++) // 这种情况只需要1和2交替出现即可
        {
            if (i & 1)
                a[i] = 1;
            else
                a[i] = 2;
        }
        for (int i = 0; i < n; i++)
            cout << a[i] << " \n"[i == n - 1];
    }
    else
    {
        auto path = [&](int x, int y) -> vector<int>
        {
            vector<int> left, right; // left和right分别为x到lca的路径和y到lca的路径
            // 先将x和y转移到二叉树的同一层中
            while ((int)log2(x) > (int)log2(y))
            {
                left.push_back(x);
                x >>= 1;
            }
            while ((int)log2(y) > (int)log2(x))
            {
                right.push_back(y);
                y >>= 1;
            }
            // 然后x和y同时向LCA转移
            while (x != y)
            {
                left.push_back(x);
                right.push_back(y);
                x >>= 1;
                y >>= 1;
            }
            // 勿忘加入LCA
            left.push_back(x);
            // 合并left和right两个数组
            for (int i = right.size() - 1; i >= 0; i--)
            {
                left.push_back(right[i]);
            }
            // 返回合并后的数组,即路径
            return left;
        };
        // 第一个值非-1的索引左侧的-1可以通过上一个值交替乘2,除2来构造
        for (int i = idx[0] - 1, cnt = 1; i >= 0; i--, cnt++)
        {
            if (cnt & 1)
                a[i] = a[i + 1] * 2;
            else
                a[i] = a[i + 1] / 2;
        }
        // 最后一个值非-1的索引右侧的-1可以通过上一个值交替乘2,除2来构造
        for (int i = idx[idx.size() - 1] + 1, cnt = 1; i < n; i++, cnt++)
        {
            if (cnt & 1)
                a[i] = a[i - 1] * 2;
            else
                a[i] = a[i - 1] / 2;
        }
        // 对于两个值非-1的索引中间的-1,找到值a[idx[i]]和a[idx[i+1]]的LCA(最近公共祖先),然后存储a[idx[i]]到a[idx[i+1]]的转移路径
        for (int i = 0; i < idx.size() - 1; i++)
        {
            int x = idx[i];
            int y = idx[i + 1];
            vector<int> res = path(a[x], a[y]);
            // 1.如果路径大小的奇偶性和数组内区间元素个数的奇偶性不同,则无法构造(因为若有剩余-1,需要交替*2,/2,而这个操作一定是偶数次)
            // 2.如果路径大小大于数组内区间元素个数,则无法构造,因为-1的数量不足够实现a[idx[i]]到a[idx[i+1]]的转移
            if (((res.size() & 1) ^ ((y - x + 1) & 1)) || (res.size() > (y - x + 1)))
            {
                cout << -1 << '\n';
                return;
            }
            // 如果可以实现构造,先将res路径更新到a数组中
            for (int j = x, cnt = 0; j < x + res.size(); j++, cnt++)
            {
                a[j] = res[cnt];
            }
            // 然后通过交替*2,/2的操作来填补剩余的-1(剩余偶数个-1)
            for (int j = x + res.size(), cnt = 1; j <= y; j++, cnt++)
            {
                if (cnt & 1)
                    a[j] = a[j - 1] * 2;
                else
                    a[j] = a[j - 1] / 2;
            }
        }
        for (int i = 0; i < n; i++)
            cout << a[i] << " \n"[i == n - 1];
    }
}

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

    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}
相关推荐
??tobenewyorker39 分钟前
力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树
数据结构·c++·算法·leetcode
贾全1 小时前
第十章:HIL-SERL 真实机器人训练实战
人工智能·深度学习·算法·机器学习·机器人
GIS小天1 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年7月4日第128弹
人工智能·算法·机器学习·彩票
oioihoii1 小时前
C++11 forward_list 从基础到精通:原理、实践与性能优化
c++·性能优化·list
满分观察网友z2 小时前
开发者的“右”眼:一个树问题如何拯救我的UI设计(199. 二叉树的右视图)
算法
m0_687399842 小时前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
森焱森3 小时前
无人机三轴稳定化控制(1)____飞机的稳定控制逻辑
c语言·单片机·算法·无人机
循环过三天3 小时前
3-1 PID算法改进(积分部分)
笔记·stm32·单片机·学习·算法·pid
Ronin3053 小时前
【C++】类型转换
开发语言·c++
闪电麦坤953 小时前
数据结构:二维数组(2D Arrays)
数据结构·算法