Skip to Content

Almost Identity Permutations

Análisis oficial 

Explicación

Podemos iterar de 00 a kk y barajar exactamente kk posiciones de la permutación. Después de barajar, exactamente kk posiciones de la permutación deberían ser distintas mientras las posiciones restantes permanecen iguales para cumplir el criterio de casi identidad.

Consideremos cómo contar las formas de barajar exactamente mm posiciones de la permutación. Primero hay que elegir exactamente mm posiciones en las permutaciones de entre nn índices, que es (nm){n \choose m}. Ahora consideremos cómo barajar las mm posiciones. Podemos considerar permutaciones. Sin embargo, en algunas permutaciones, no todas las posiciones están completamente barajadas.

Por ejemplo, si n=4n = 4.

La permutación identidad será 11 22 33 44.

Digamos que queremos reordenar los primeros 3 elementos.

Una permutación posible es: 11 33 22 44.

En esta permutación, el primer elemento sigue en el mismo lugar, que no es el resultado deseado (no barajamos todos los elementos que queremos reordenar).

Así, necesitamos hallar todas las permutaciones donde todos los elementos están fuera de lugar. Sin embargo, como kk es relativamente pequeño, podemos hacer fuerza bruta sobre las permutaciones para hallar el número de permutaciones válidas.

Podemos sumar el número de permutaciones válidas multiplicado por el número de formas de elegir una permutación de esa longitud.

Implementación

Complejidad temporal: O(NK)\mathcal{O}(NK)

#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { int n, k; cin >> n >> k; // Use Pascal's Identity to precalculate combinations. ll c[n + 1][k + 1]; fill_n(&c[0][0], (n + 1) * (k + 1), 0); for (int i = 0; i <= n; i++) { c[i][0] = 1; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= k; j++) { c[i][j] = c[i - 1][j] + c[i - 1][j - 1]; } } ll ans = 0; // Iterate over number of positions to shuffle. for (int i = 0; i <= k; i++) { // Calculate number of valid permutations result in all positions // shuffled. int a[i]; for (int j = 0; j < i; j++) a[j] = j; int amt = 0; do { bool valid = 1; for (int j = 0; j < i; j++) if (a[j] == j) valid = 0; if (valid) amt++; } while (next_permutation(a, a + i)); // Add the number of valid permutations of i elements multiplied by the // number of ways to choose i elements. ans += c[n][i] * amt; } cout << ans << endl; }