Codeforces Round 992 (Div. 2) 解題報告

talentestors發表於2024-12-09

比賽地址: https://codeforces.com/contest/2040

A. Game of Division

題目

https://codeforces.com/contest/2040/problem/A

題意

給你一個長度為 \(n\) 的整數陣列 \(a_1, a_2, \ldots, a_n\) 和一個整數陣列 \(k\)

兩個玩家正在玩一個遊戲。第一個玩家選擇一個索引 \(1 \le i \le n\) 。然後第二個玩家選擇不同的索引 \(1 \le j \le n, i \neq j\) 。如果 \(|a_i - a_j|\) 不能被 \(k\) 整除,則第一個玩家獲勝。否則,第二位棋手獲勝。

我們扮演第一個玩家。確定是否可能獲勝,如果可能,應該選擇哪個索引 \(i\)

數字 \(x\) 的絕對值用 \(|x|\) 表示,如果是 \(x \ge 0\) ,則等於 \(x\) ,否則等於 \(-x\)

思路

模擬

AC程式碼

點選檢視程式碼
#define _USE_MATH_DEFINES // To use the definition of cmath

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using ull = unsigned long long;

// mp.reserve(1024), mp.max_load_factor(0.75);
// Used only for basic types, pair and tuple.
template<typename T>
struct custom_hash_base {
    size_t operator()(const T& x) const {
        static const size_t seed = chrono::steady_clock::now().time_since_epoch().count();
        return _Hash_bytes(&x, sizeof(x), seed);
    }
};

static const auto _ = []() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifndef ONLINE_JUDGE
    freopen("../in.txt", "r", stdin);
#endif
    return nullptr;
}();

int nums[101], k;
int n;
int st[101];

inline void solve() {
    cin >> n >> k;
    memset(st, 0, sizeof(int) * (k + 1));
    for (int i = 1; i <= n; ++i) {
        cin >> nums[i];
    }
    for (int i = 1; i <= n; ++i) {
        bool flag = true;
        for (int j = 1; j <= n && flag; ++j) {
            if (i == j) continue;
            if (abs(nums[i] - nums[j]) % k == 0) flag = false;
        }
        if (flag) {
            cout << "YES\n" << i << "\n";
            return;
        }
    }
    cout << "NO\n";
}

int main() {
    int T;
    for (cin >> T; T > 0; --T) {
        solve();
    }
    return 0;
}

B. Paint a Strip

題目

https://codeforces.com/contest/2040/problem/B

題意

您有一個長度為 \(n\) 的零陣列 \(a_1, a_2, \ldots, a_n\)

你可以對它進行兩種操作:

  1. \(1 \le i \le n\)\(a_i = 0\) 之間選擇一個索引 \(i\) ,並將 \(1\) 賦值給 \(a_i\)
  2. 選擇一對索引 \(l\)\(r\) ,使得 \(1 \le l \le r \le n\)\(a_l = 1\)\(a_r = 1\)\(a_l + \ldots + a_r \ge \lceil\frac{r - l + 1}{2}\rceil\) ,並將所有 \(l \le i \le r\)\(1\) 賦值給 \(a_i\)

要使陣列中的所有元素都等於 1,至少需要進行多少次第一種型別的運算?

思路

\(i\) 次第一種型別的運算,可覆蓋的最大範圍為第 \(i - 1\) 次的範圍加1,再乘2。

先初始化每一個i的範圍,再二分查詢。

AC程式碼

點選檢視程式碼
#define _USE_MATH_DEFINES // To use the definition of cmath

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using ull = unsigned long long;

// mp.reserve(1024), mp.max_load_factor(0.75);
// Used only for basic types, pair and tuple.
template<typename T>
struct custom_hash_base {
    size_t operator()(const T& x) const {
        static const size_t seed = chrono::steady_clock::now().time_since_epoch().count();
        return _Hash_bytes(&x, sizeof(x), seed);
    }
};

static const auto _ = []() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifndef ONLINE_JUDGE
    freopen("../in.txt", "r", stdin);
#endif
    return nullptr;
}();

int n;
constexpr int N = 20;
ll st[N];

static const auto init= []() {
    st[1] = 1;
    for (int i = 2; i < N; ++i) {
        st[i] = (st[i - 1] + 1) << 1;
    }
    return 0;
}();

inline void solve() {
    cin >> n;
    int p = lower_bound(st + 1, st + N, n) - st - 1;
    while (st[p] < n) ++p;
    cout << p << '\n';
}

int main() {
    int T;
    for (cin >> T; T > 0; --T) {
        solve();
    }
    return 0;
}

C. Ordered Permutations

題目

https://codeforces.com/contest/2040/problem/C

  • time limit per test: 2 seconds
  • memory limit per test: 256 megabytes
  • input: standard input
  • output: standard output

Consider a permutation\(^{\text{∗}}\) \(p_1, p_2, \ldots, p_n\) of integers from \(1\) to \(n\). We can introduce the following sum for it\(^{\text{†}}\):

\[S(p) = \sum_{1 \le l \le r \le n} \min(p_l, p_{l + 1}, \ldots, p_r) \]

Let us consider all permutations of length \(n\) with the maximum possible value of \(S(p)\). Output the \(k\)-th of them in lexicographical\(^{\text{‡}}\)order, or report that there are less than \(k\) of them.

\(^{\text{∗}}\)A permutation of length \(n\) is an array consisting of \(n\) distinct integers from \(1\) to \(n\) in arbitrary order. For example, \([2,3,1,5,4]\) is a permutation, but \([1,2,2]\) is not a permutation (\(2\) appears twice in the array), and \([1,3,4]\) is also not a permutation (\(n=3\) but there is \(4\) in the array).

\(^{\text{†}}\)For example:

  • For the permutation \([1, 2, 3]\) the value of \(S(p)\) is equal to \(\min(1) + \min(1, 2) + \min(1, 2, 3) + \min(2) + \min(2, 3) + \min(3) =\) \(1 + 1 + 1 + 2 + 2 + 3 = 10\)
  • For the permutation \([2, 4, 1, 3]\) the value of \(S(p)\) is equal to \(\min(2) + \min(2, 4) + \min(2, 4, 1) + \min(2, 4, 1, 3) \ +\) $ \min(4) + \min(4, 1) + \min(4, 1, 3) \ +$ \(\min(1) + \min(1, 3) \ +\) \(\min(3) =\) \(2 + 2 + 1 + 1 + 4 + 1 + 1 + 1 + 1 + 3 = 17\).

\(^{\text{‡}}\)An array \(a\) is lexicographically smaller than an array \(b\) if and only if one of the following holds:

  • \(a\) is a prefix of \(b\), but \(a \ne b\); or
  • in the first position where \(a\) and \(b\) differ, the array \(a\) has a smaller element than the corresponding element in \(b\).

Input

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

The only line of each test case contains two integers \(n\) and \(k\) (\(1 \le n \le 2 \cdot 10^5\); \(1 \le k \le 10^{12}\)) — the length of the permutation and the index number of the desired permutation.

It is guaranteed that the sum of \(n\) over all test cases does not exceed \(2 \cdot 10 ^ 5\).

Output

For each test case, if there are less than \(k\) suitable permutations, print \(-1\).

Otherwise, print the \(k\)-th suitable permutation.

Example

點選檢視測試樣例

Input

6
3 2
3 3
4 11
4 6
6 39
7 34

Output

1 3 2
2 3 1
-1
2 4 3 1
-1
2 3 4 5 7 6 1

Note

Let us calculate the required sum for all permutations of length \(3\) (ordered lexicographically):

Permutation Value of \(S(p)\)
\([1, 2, 3]\) \(10\)
\([1, 3, 2]\) \(10\)
\([2, 1, 3]\) \(9\)
\([2, 3, 1]\) \(10\)
\([3, 1, 2]\) \(9\)
\([3, 2, 1]\) \(10\)

In the first test case, you have to print the second suitable permutation of length \(3\). Looking at the table, we see that it is the permutation \([1, 3, 2]\).

In the second test case, you have to print the third suitable permutation of length \(3\). Looking at the table, we see that it is the permutation \([2, 3, 1]\).

題意

考慮從 \(1\)\(n\) 的整數 \(^{\text{∗}}\) 的排列。從 \(1\)\(n\) 的整數的排列組合 \(p_1, p_2, \ldots, p_n\) 。我們可以為它引入下面的和 \(^{\text{†}}\)

\[S(p) = \sum_{1 \le l \le r \le n} \min(p_l, p_{l + 1}, \ldots, p_r) \]

讓我們考慮所有長度為 \(n\) 的排列,其最大可能值為 \(S(p)\) 。按詞典 \(^{\text{‡}}\) 順序輸出其中的第 \(k\) 個,或者報告它們的數量少於 \(k\)

\(^{\text{∗}}\) 長度為 \(n\) 的排列是由 \(n\) 個不同的整陣列成的陣列,這些整數從 \(1\)\(n\) 按任意順序排列。例如, \([2,3,1,5,4]\) 是一個排列,但 \([1,2,2]\) 不是一個排列( \(2\) 在陣列中出現了兩次), \([1,3,4]\) 也不是一個排列( \(n=3\) ,但陣列中有 \(4\) )。

\(^{\text{†}}\) 例如

  • 對於 \([1, 2, 3]\) 這個排列, \(S(p)\) 的值等於 \(\min(1) + \min(1, 2) + \min(1, 2, 3) + \min(2) + \min(2, 3) + \min(3) =\)\(1 + 1 + 1 + 2 + 2 + 3 = 10\)
  • 對於排列 \([2, 4, 1, 3]\) 來說, \(S(p)\) 的值等於 \(\min(2) + \min(2, 4) + \min(2, 4, 1) + \min(2, 4, 1, 3) \ +\) $ \min(4) + \min(4, 1) + \min(4, 1, 3) \ +$ 。 \(\min(1) + \min(1, 3) \ +\) \(\min(3) =\) \(2 + 2 + 1 + 1 + 4 + 1 + 1 + 1 + 1 + 3 = 17\) .

\(^{\text{‡}}\) 當且僅當以下條件之一成立時,陣列 \(a\) 的lexicographically小於陣列 \(b\)

  • \(a\)\(b\) 的字首,但是 \(a \ne b\) ;或者
  • \(a\)\(b\) 不同的第一個位置,陣列 \(a\) 中的元素小於 \(b\) 中的相應元素。

輸入

每個測試包含多個測試用例。第一行包含測試用例的數量 \(t\) ( \(1 \le t \le 10^4\) )。測試用例說明如下。

每個測試用例的唯一一行包含兩個整數 \(n\)\(k\)\(1 \le n \le 2 \cdot 10^5\) ;{47522742})。( \(1 \le n \le 2 \cdot 10^5\) ; \(1 \le k \le 10^{12}\) ) - 排列的長度和所需排列的索引號。

保證所有測試用例中 \(n\) 的總和不超過 \(2 \cdot 10 ^ 5\)

輸出

對於每個測試用例,如果合適的排列組合少於 \(k\) ,則列印 \(-1\)

否則,列印 \(k\) 個合適的排列。

備註

讓我們計算所有長度為 \(3\) (按詞典順序排列)的排列所需的和:

Permutation \(S(p)\) 的值
\([1, 2, 3]\) \(10\)
\([1, 3, 2]\) \(10\)
\([2, 1, 3]\) \(9\)
\([2, 3, 1]\) \(10\)
\([3, 1, 2]\) \(9\)
\([3, 2, 1]\) \(10\)

在第一個測試用例中,您必須列印長度為 \(3\) 的第二個合適的排列。觀察表格,我們會發現是長度為 \([1, 3, 2]\) 的排列。

在第二個測試用例中,您必須列印長度為 \(3\) 的第三個合適的排列。觀察表格,我們會發現是長度為 \([2, 3, 1]\) 的排列。

思路

透過打表,可以觀察到。值為最大的 \(S(p)\) 排列的數量\(2^{n - 1}\)

所以只要值為最大的 \(S(p)\) 排列的數量不超過 \(k\) 則有解,否則輸出 -1

這裡給出 \(n\) 為 5 的情況:

 1: 1 2 3 4 5 = 35

 2: 1 2 3 5 4 = 35

 3: 1 2 4 5 3 = 35
 4: 1 2 5 4 3 = 35

 5: 1 3 4 5 2 = 35
 6: 1 3 5 4 2 = 35
 7: 1 4 5 3 2 = 35
 8: 1 5 4 3 2 = 35

 9: 2 3 4 5 1 = 35
10: 2 3 5 4 1 = 35
11: 2 4 5 3 1 = 35
12: 2 5 4 3 1 = 35
13: 3 4 5 2 1 = 35
14: 3 5 4 2 1 = 35
15: 4 5 3 2 1 = 35
16: 5 4 3 2 1 = 35

假設 \(k\) 取 7:0b0111

會發現 7 是從 3:0b0011 的後 3 位,往前挪動 1 位形成的。

而 3 是從 1:0b0001 的後兩位,往前挪動 1 位形成的。

同樣的 4:0b0100 是以同樣的方式從 2:0b0010 轉移過來的。


得出結論:第 \(k\) 個排列是第 prev_k(把 \(k\) 移除二進位制的最高位,如果二進位制bit 1的個數為1則左移1位)個排列的後 m(k 二進位制的最左邊1的位置) 位往前挪動1位形成的。

AC程式碼

點選檢視程式碼
#define _USE_MATH_DEFINES // To use the definition of cmath

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using ull = unsigned long long;

// mp.reserve(1024), mp.max_load_factor(0.75);
// Used only for basic types, pair and tuple.
template<typename T>
struct custom_hash_base {
    size_t operator()(const T& x) const {
        static const size_t seed = chrono::steady_clock::now().time_since_epoch().count();
        return _Hash_bytes(&x, sizeof(x), seed);
    }
};

static const auto _ = []() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifndef ONLINE_JUDGE
    freopen("../in.txt", "r", stdin);
#endif
    return nullptr;
}();

ll n, k;

inline ll get_next(ll x) {
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x |= x >> 32;
    ++x;
    return x;
}

inline void dfs(ll ck, vector<ll>& v) {
    if (ck <= 1)
        return;
    if (__builtin_popcountll(ck) == 1)
        dfs(ck >> 1, v);
    else
        dfs(ck - (get_next(ck) >> 1), v);
    ck = get_next(ck);
    int i = 64 - __builtin_clzll(ck) - 1;
    ll x = v[i];
    v.erase(v.begin() + i);
    v.insert(v.begin(), x);
}

inline void solve() {
    cin >> n >> k;
    const int ci = 64 - __builtin_clzll(get_next(k));
    if (n < ci) {
        cout << -1 << '\n';
        return;
    }
    vector<ll> v(n);
    iota(v.rbegin(), v.rend(), 1LL);
    dfs(k, v);
    ranges::reverse(v);
    ranges::copy(v, ostream_iterator<ll>(cout, " "));
    cout << '\n';
}

int main() {
    int T;
    for (cin >> T; T > 0; --T) {
        solve();
    }
    return 0;
}

閱讀原文

相關文章