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;
}
相关推荐
白榆maple25 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少29 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧2 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
ULTRA??3 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++