Cod sursa(job #2937687)

Utilizator Alex_tz307Lorintz Alexandru Alex_tz307 Data 10 noiembrie 2022 20:18:58
Problema Sortari2 Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.82 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("sortari2.in");
ofstream fout("sortari2.out");

const int mod = 999017;

void addSelf(int &x, int y) {
  x += y;
  if (x >= mod) {
    x -= mod;
  }
}

void multSelf(int &x, int y) {
  x = (int64_t)x * y % mod;
}

int mult(int x, int y) {
  multSelf(x, y);
  return x;
}

/*
  (1) Numarul minim de swap-uri adiacente necesare pentru a sorta o permutare este egal cu cel
      al inversiunilor.

  (2) Numarul minim de swap-uri de orice fel necesare pentru a sorta o permutare este egal cu
      n - numarul_de_cicluri_al_permutarii.

  Prima valoare va fi mereu mai mare sau egala decat a doua pentru orice permutare(de fiecare data
  cand fac un swap care imi creste cu 1 numarul de inversiuni, numarul de cicluri poate sa scada
  cu maxim 1 si pentru permutarea identica(deja sortata) ambele valori sunt 0).

  Astfel, pentru a numara cate permutari au valoarea (2) strict mai mica decat (1), pot sa scad din
  numarul total de permutari(n!) cele care le au egale.

  Conditia se poate rescrie ca numarul_de_inversiuni + numarul_de_cicluri = n.
  Observatie: Pentru o permutare oarecare numarul_de_inversiuni + numarul_de_cicluri >= n(din (1) si (2)).

  Observatie: n trebuie mereu sa se afle intr-un ciclu cu un sufix. Daca asta nu s-ar intampla,
              numarul_de_inversiuni + numarul_de_cicluri ar fi > n(la un moment dat n ar adauga
              o inversiune, dar nu ar scadea numarul de cicluri).
*/

/*
  Exemplu:

  1 2 3 | 4 5
  1 2 3 | 5 4

  1 2 | 3 4 5
  1 2 | 5 3 4

  1 2 | 3 4 5
  1 2 | 4 5 3
*/

int main() {
  int n;
  fin >> n;
  vector<int> cycles(n + 1);
  // cycles[i] =def= numarul de cicluri de lungime i cu i - 1 inversiuni
  cycles[1] = 1;
  cycles[2] = 1;
  for (int i = 3; i <= n; ++i) {
    // Iau un ciclu de lungime mai mica si il inserez pe i unde trebuie pentru a forma numarul
    // necesar de noi inversiuni.
    // => cycles[i] = cycles[i - 1] + cycles[i - 2] + cycles[i - 3] + ... cycles[1]
    // Se observa ca cycles[3] = cycles[1] + cycles[2]
    // => cycles[4] = 2 * cycles[3]
    // Inductiv se ajunge la cycles[i] = cycles[i - 1] * 2
    cycles[i] = mult(cycles[i - 1], 2);
  }
  vector<int> dp(n + 1);
  dp[0] = 1;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= i; ++j) {
      // Fixez dimensiunea ciclului din care face parte n(care e cum am precizat anterior un sufix)
      // Observatie: Numar solutii unice pentru ca mereu sufixele vor avea numar diferit de
      // invsersiuni, deci vor fi diferite(vezi exemplu mai sus).
      addSelf(dp[i], mult(dp[i - j], cycles[j]));
    }
  }
  int res = 1;
  for (int i = 1; i <= n; ++i) {
    multSelf(res, i);
  }
  addSelf(res, mod - dp[n]);
  fout << res << '\n';
  fin.close();
  fout.close();
  return 0;
}