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;
}
相关推荐
xlp666hub1 天前
Leetcode第一题:用C++解决两数之和问题
c++·leetcode
ZhengEnCi1 天前
08c. 检索算法与策略-混合检索
后端·python·算法
程序员小崔日记1 天前
大三备战考研 + 找实习:我整理了 20 道必会的时间复杂度题(建议收藏)
算法·408·计算机考研
lizhongxuan1 天前
AI小镇 - 涌现
算法·架构
AI工程架构师1 天前
通常说算力是多少 FLOPS,怎么理解,GPU和CPU为什么差异这么大
算法
不想写代码的星星1 天前
C++继承、组合、聚合:选错了是屎山,选对了是神器
c++
祈安_1 天前
Java实现循环队列、栈实现队列、队列实现栈
java·数据结构·算法
归去_来兮2 天前
拉格朗日插值算法原理及简单示例
算法·数据分析·拉格朗日插值
千寻girling2 天前
Python 是用来做 AI 人工智能 的 , 不适合开发 Web 网站 | 《Web框架》
人工智能·后端·算法
颜酱2 天前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法