Редакция для Циклический сдвиг влево


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Автор: montes332

1. Идея

Нужно выполнить циклический сдвиг массива влево на k позиций.

Это означает, что:

  • первые k элементов уходят в конец,
  • элементы с позиции k до n - 1 переходят в начало.

Например, если массив 1 2 3 4 5 и k = 2, то после сдвига получим:

  • в начало идут элементы 3 4 5,
  • затем дописываются 1 2.

Итог: 3 4 5 1 2.

Главная тонкость в том, что k может быть очень большим, поэтому нельзя просто сдвигать по одному много раз.


2. Наблюдения

Наблюдение 1. Сдвиг на n позиций ничего не меняет

Если массив длины n, то после сдвига влево на n элементов он останется тем же самым.

Значит, сдвиг на k позиций эквивалентен сдвигу на k % n.

Например, при n = 5:

  • сдвиг на 7 — это то же самое, что сдвиг на 2,
  • потому что 7 % 5 = 2.

Наблюдение 2. Ответ — это просто склейка двух частей массива

После того как мы заменили k на k % n, ответ можно записать так:

  • сначала элементы a[k], a[k+1], ..., a[n-1],
  • потом элементы a[0], a[1], ..., a[k-1].

То есть ответ равен a[k:] + a[:k].


3. Алгоритм

  1. Считать n и k.
  2. Считать массив a из n чисел.
  3. Вычислить k %= n.
  4. Вывести элементы массива в таком порядке:
    • сначала от a[k] до a[n-1],
    • затем от a[0] до a[k-1].

4. Почему это работает

После циклического сдвига влево на 1:

  • первый элемент переносится в конец,
  • остальные сдвигаются на одну позицию влево.

Если сделать такой сдвиг k раз, то первые k элементов по очереди окажутся в конце, сохранив порядок. Все остальные элементы просто сдвинутся ближе к началу.

Именно поэтому итоговый массив состоит из двух подряд идущих частей:

  • хвост исходного массива, начиная с позиции k,
  • затем начало массива длины k.

Замена k на k % n корректна, потому что каждый полный сдвиг на n позиций возвращает массив в исходное состояние. Значит, важен только остаток от деления k на n.

Следовательно, алгоритм выводит ровно тот массив, который получается после циклического сдвига влево на k позиций.


5. Сложность

  • Время: O(n), потому что каждый элемент выводится ровно один раз.
  • Память:
    • O(n) на хранение массива.
    • В Python в приведённом решении ещё создаётся результирующий список длины n, так что память тоже O(n).

6. Код на C++17

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    long long k;
    cin >> n >> k;

    vector<long long> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    k %= n;

    bool first = true;
    for (int i = (int)k; i < n; i++) {
        if (!first) cout << ' ';
        cout << a[i];
        first = false;
    }
    for (int i = 0; i < (int)k; i++) {
        if (!first) cout << ' ';
        cout << a[i];
        first = false;
    }
    cout << '\n';

    return 0;
}

7. Код на Python 3

n, k = map(int, input().split())
a = list(map(int, input().split()))

k %= n
res = a[k:] + a[:k]
print(*res)

Комментарии

Еще нет ни одного комментария.