PKU 3705 - Reverse

問題概要

nが入力される。
1, 2, ..., nの昇順数列をn, n-1, ..., 1の降順数列にするための最小の操作数と、操作方法を出力せよ。
数列に対する1回の操作では、次のことをできる。

  • (pos1, length, pos2)
    • まず、数列のpos1番目からlength個を取り出す。
    • 次に、取り出した後の数列のpos2番目の要素の直後に、先ほど取り出したlength個の要素を挿入する。

解法

  • n=1の場合
    • 0回ですね
  • n=2の場合
    • 1回ですね

n>=3の場合、必ずn/2+1回で降順にできます。具体例を見ていただければ、わかりやすいです。

  • n=5(奇数)の場合
    • 1 2 3 4 5 -> 3 4 1 2 5
    • 3 4 1 2 5 -> 3 2 5 4 1
    • 3 2 5 4 1 -> 5 4 3 2 1
  • n=6(偶数)の場合
    • 1 2 3 4 5 6 -> 3 4 1 2 5 6
    • 3 4 1 2 5 6 -> 3 2 5 4 1 6
    • 3 2 5 4 1 6 -> 3 2 1 6 5 4
    • 3 2 1 6 5 4 -> 6 5 4 3 2 1

つまり、n/2以下の要素の降順を左側に寄せて、n/2より大きい要素の降順を右側に寄せるように操作しています。そして、最後に右半分を一番左に挿入してやればいいわけです。

プログラム

#include <iostream>
using namespace std;

int main(){
  int n;

  while(cin >> n){
    if(n == 1){
      cout << 0 << endl;
      continue;
    }
    if(n == 2){
      cout << "1" << endl;
      cout << "1 1 1" << endl;
      continue;
    }

    cout << n / 2 + 1 << endl;

    for(int i = 1; i <= n / 2; i++){
      cout <<  (n - 1) / 2 + i << " " << 2 << " " << i - 1 << endl;
    }
    cout << n / 2 + 1 << " " << n / 2 << " " << 0 << endl;
  }
}