首页 > 其他分享 >D. Array Repetition

D. Array Repetition

时间:2024-01-19 21:24:35浏览次数:29  
标签:sz 10 array leq test Array Repetition 节点

D. Array Repetition

Jayden has an array $a$ which is initially empty. There are $n$ operations of two types he must perform in the given order.

  1. Jayden appends an integer $x$ ($1 \leq x \leq n$) to the end of array $a$.
  2. Jayden appends $x$ copies of array $a$ to the end of array $a$. In other words, array $a$ becomes $[a,\underbrace{a,\ldots,a}_{x}]$. It is guaranteed that he has done at least one operation of the first type before this.

Jayden has $q$ queries. For each query, you must tell him the $k$-th element of array $a$. The elements of the array are numbered from $1$.

Input

Each test consists of multiple test cases. The first line contains a single integer $t$ ($1 \leq t \leq 5000$) — the number of test cases. The description of the test cases follows.

The first line of each test case contains two integers $n$ and $q$ ($1 \leq n, q \leq 10^5$) — the number of operations and the number of queries.

The following $n$ lines describe the operations. Each line contains two integers $b$ and $x$ ($b \in \{1, 2\}$), where $b$ denotes the type of operation. If $b=1$, then $x$ ($1 \leq x \leq n$) is the integer Jayden appends to the end of the array. If $b=2$, then $x$ ($1 \leq x \leq 10^9$) is the number of copies Jayden appends to the end of the array.

The next line of each test case contains $q$ integers $k_1, k_2, \ldots, k_q$ ($1 \leq k_i \leq \min(10^{18}, c)$), which denote the queries, where $c$ is the size of the array after finishing all $n$ operations.

It is guaranteed that the sum of $n$ and the sum of $q$ over all test cases does not exceed $10^5$.

Output

For each test case, output $q$ integers — answers to Jayden's queries.

Example

input

4
5 10
1 1
1 2
2 1
1 3
2 3
1 2 3 4 5 6 14 15 16 20
10 10
1 3
1 8
2 15
1 6
1 9
1 1
2 6
1 1
2 12
2 10
32752 25178 3198 3199 2460 2461 31450 33260 9016 4996
12 5
1 6
1 11
2 392130334
1 4
2 744811750
1 10
1 5
2 209373780
2 178928984
1 3
2 658326464
2 1000000000
914576963034536490 640707385283752918 636773368365261971 584126563607944922 1000000000000000000
2 2
1 1
1 2
1 2

output

1 2 1 2 3 1 2 3 1 3
9 8 1 3 1 3 6 3 8 8
11 11 11 10 11
1 2

Note

In the first test case:

  • After the first operation $a = [1]$;
  • After the second operation $a = [1, 2]$;
  • After the third operation $a = [1, 2, 1, 2]$;
  • After the fourth operation $a = [1, 2, 1, 2, 3]$;
  • After the fifth operation $a = [1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3]$.

In the fourth test case, after all operations $a = [1, 2]$.

 

解题思路

  首先我们不可能根据操作把数组 $a$ 模拟建出来,否则时间和空间复杂度都会爆掉,意味着一定是通过“压缩”的方式来存储数组 $a$ 的信息。

  考虑用链式结构依次存储每个状态 $a$ 的信息,那么每个节点存储哪些参数呢?对于操作 $2$,显然要记录拷贝前 $a$ 的大小(也就是当前 $a$ 的大小),记作 $sz$,以及拷贝后的数量 $x+1$,记作 $c$。这样对于当前节点的两个参数 $sz$ 与 $c$,就可以得知当前的 $a$ 是将前一个节点所表示的数组拷贝 $c$ 份得到的,大小为 $sz \cdot c$。

  另外对于操作 $1$,我们还需要在节点中记录数组的最后一个元素是什么,如果有连续的操作 $1$,为了避免开额外的节点我们在节点中用一个 std::vector 来记录连续的操作 $1$ 压入的元素,只有在操作 $2$ 时才开新的节点。由于询问的下标不超过 $10^{18}$ 这样做就可以保证在 $n$ 次操作后节点的数量不超过 $61$ 个(因为 $2^{61} > 10^{18}$,同时当数组 $a$ 的大小不超过 $10^{18}$ 才执行操作)。

  因此新的节点的参数 $sz$ 就是前一个节点的 $sz \cdot c + \text{size}(q)$,$\text{size}(q)$ 是std::vector 的大小。另外只有在当前数组大小不超过 $10^{18}$ 时才进行拷贝,同时还要保证拷贝后的数组大小不超过 $10^{18}$,即新节点的参数 $c$ 实际上应该是 $\min\left\{ x+1, \, \left\lceil \frac{10^{18}}{sz} \right\rceil \right\}$,这里的 $sz$ 是新节点的。

  对于询问 $x$,只需从后往前依次枚举每个节点,对于当前节点状态的数组,记 $s = sz \cdot c$,表示上一个状态的数组拷贝了 $c$ 份后的大小。如果 $x \in \left[  s + 1, \, s + \text{size}(q) \right]$,那么很明显答案就是 $q[x-s-1]$。否则 $x$ 的位置在某份拷贝的数组中(即大小为 $sz$ 的数组),令 $x \gets (x-1) \bmod sz + 1$,得到其所在拷贝的数组的下标,然后遍历到前一个节点用同样的方法继续处理。

  AC 代码如下,时间复杂度为 $O(q \cdot \log{A})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

struct Node {
    LL sz, c;
    vector<int> q;
};

void solve() {
    int n, m;
    cin >> n >> m;
    vector<Node> p({{0}});
    while (n--) {
        int op, x;
        cin >> op >> x;
        if (op == 1) {
            p.back().q.push_back(x);
        }
        else {
            LL sz = p.back().sz * p.back().c + p.back().q.size();
            if (sz < (LL)1e18) p.push_back({sz, min(x + 1ll, ((LL)1e18 + sz - 1) / sz)});
        }
    }
    while (m--) {
        LL x;
        cin >> x;
        for (int i = p.size() - 1; i >= 0; i--) {
            LL sz = p[i].sz * p[i].c;
            if (x > sz) {
                cout << p[i].q[x - sz - 1] << ' ';
                break;
            }
            else {
                x = (x - 1) % p[i].sz + 1;
            }
        }
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 919 (Div. 2) 题解:https://www.cnblogs.com/zsc985246/p/17963255

  Editorial for Codeforces Round #919 (Div. 2):https://codeforces.com/blog/entry/122560

标签:sz,10,array,leq,test,Array,Repetition,节点
From: https://www.cnblogs.com/onlyblues/p/17975392

相关文章

  • Java里ArrayList中的toArray()用法
    深入理解List的toArray()方法和toArray(T[]a)方法这两个方法都是将列表List中的元素转导出为数组,不同的是,toArray()方法导出的是Object类型数组,而toArray[T[]a]方法导出的是指定类型的数组。下面是两个方法的申明及说明,摘自Java8的API文档。toArray()方法的分析Object[]toA......
  • 15 Friendly Arrays
    FriendlyArrays打表#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;voidsolve(){ intn,m; cin>>n>>m; vector<int>a(n+1); vector<int>b(m+1); for(inti=1;i<=n;i++)cin>>a[i]; for(inti=1;i<......
  • Stack-array based implementation【1月17日学习笔记】
    点击查看代码//Stack-arraybasedimplementation#include<iostream>usingnamespacestd;#defineMAX_SIZE101intA[MAX_SIZE];//globleinttop=-1;//globlevoidpush(intx){ if(top==MAX_SIZE-1){ cout<<"error:stackoverflow"&l......
  • D. Array Repetition
    原题链接核心大事实1:对于查询的点k对应的值一定是某个操作过后的最后一个值核心大事实2:对于操作前数组长度大于k的都不用考虑核心小事实:点k有两种情况1.点k的位置在两次操作之间(乘法)2.点k的位置恰好位于某次操作后的最后一个点(乘法和加法都有可能)代码构建以此展开1.要不断......
  • 数组Array
    slice用于截取数组的一部分,不修改原数组。letmyArray=[1,2,3,4,5];//使用slice创建一个新的数组,包含索引1到索引3的元素(不包括索引3)letnewArray=myArray.slice(1,3);console.log(newArray);//输出新的数组,这里是[2,3]console.log(myArray);//输出原始数......
  • Codeforces Round 920 (Div. 3) D Very Different Array
    DVeryDifferentArray题意给出两个长度分别为\(n,m\)的数组\(a,c\),\(n<m\),从\(c\)中选择\(n\)个数并找到一个序列使得\(D=\sum_{i=1}^{n}|a_i-c_i|\)尽可能大,求D的值思路假设如果\(m\)和\(n\)一样大,那么找到这个序列的方法很简单:将两个序列分别排序后将其中一个转置,......
  • 算法练习 1.寻找中心下标(Find the Middle Index in Array)
    算法练习1.寻找中心下表(FindtheMiddleIndexinArray)题目来源来源:力扣(LeetCode)https://leetcode-cn.com/problems/find-the-middle-index-in-array/题目描述给你一个整数数组nums,请计算数组的中心下标。数组中心下标是数组的一个下标,其左侧所有元素相加的和等于右侧所有......
  • C. Partitioning the Array
    原题链接直接看代码#include<bits/stdc++.h>usingnamespacestd;inta[200005]={0};intn;intcheck(intk){intm=0;//任何数与零的gcd都是其本身for(inti=1;i<=n-k;i++){m=__gcd(m,abs(a[i]-a[i+k]));//从题干推出来的性质?对于所有abs(a[i]-a......
  • 性能篇:深入源码解析和性能测试arraylist和LinkedList差异!
    嗨,大家好,我是小米!今天我们要谈论的是Java中两个常用的集合类:ArrayList和LinkedList。大家都知道,这两者在新增和删除元素的操作上有一些差异,那么它们究竟在性能上有何表现呢?我们通过深入源码解析和性能测试来一探究竟!ArrayList新增元素到末尾这是最常见的新增元素操作,我们使用......
  • 433. 最小基因变化(Queue使用ArrayList和LinkedList进行声明)
    这道题可以看成一个24叉树。因为基因序列长度固定为8,且每个位置的字母固定是AGCT,可以选择改变的只有3个字母,所以一次最多24种情况。然后检查变化后的结果是否存在bank中(使用hashSet来存储),同时设置一个visited集合来检查是否访问过。classSolution{publicintminMutation(St......