Мутація#4973

Мутація (Розбір)

Перестановку генів слід виконати таким чином, щоб однакові гени розташовувалися поруч. При цьому необхідно мінімізувати кількість виконаних операцій.

Кожному натуральному числу a_i поставимо у відповідність відрізок [s_i; e_i], де s_i — позиція, на якій a_i зустрічається вперше, а e_i — позиція, на якій a_i зустрічається в останній раз.

Нехай — найбільше можливе число непересічних відрізків. Це значення можна знайти за допомогою алгоритму "вибору заявок", що означає, що кожен із залишених відрізків перетинається хоча б з одним із обраних. Після цього потрібно виконати описану процедуру над генами, яким ці відрізки відповідають.

Якщо — загальна кількість побудованих відрізків. Тоді відповіддю на задачу буде значення k - res.

Приклад

Для наведеного прикладу відрізки матимуть вигляд (нумерація позицій починається з нуля):

Відсортуємо відрізки по координаті кінця:

[0; 4], [3; 5], [1; 6], [7; 7], [8; 8]

Максимальна кількість непересічних відрізків дорівнює . Наприклад, можна вибрати відрізки [0; 4], [7; 7], [8; 8]. Для генів, відповідних залишеним відрізкам, слід виконати процедуру, описану в умові задачі. До таких генів належать і . Дві перестановки можна виконати, наприклад, наступним чином:

Реалізація алгоритму

Нехай — максимальна можлива кількість геномів у вхідній послідовності.

#define MAX 100001

Вектор пар зберігає відрізки [s_i; e_i].

vector<pair<int, int> > v;
int s[MAX], e[MAX];

Читаємо вхідні дані. Ініціалізуємо s_i = -1, e_i = -1.

scanf("%d", &n);
memset(s, -1, sizeof(s));
memset(e, -1, sizeof(e));

for (i = 0; i < n; i++)
{
  scanf("%d", &x);

Якщо число зустрічається вперше, то його позицію у вхідній послідовності записуємо в s_x.

  if (s[x] == -1) s[x] = i;

Якщо число зустрічається не вперше, то його позицію записуємо в e_x, вважаючи, що зустрічається в останнє.

  if (i > e[x]) e[x] = i;
}

Усі побудовані відрізки заносимо в вектор .

for (i = 1; i <= n; i++) // numbers 1..n
  if (s[i] != -1) v.push_back(make_pair(e[i], s[i]));

Відрізки заносяться в вектор у зворотному порядку (у вигляді [e_i; s_i]), щоб за замовчуванням сортування відрізків відбувалося в порядку зростання їх кінців.

sort(v.begin(), v.end());

Знаходимо максимальну кількість непересічних відрізків.

i = res = 0;
while (i < v.size())
{

Додаємо -й відрізок у множину непересічних відрізків. Змінна містить кінець цього відрізка (назвемо його поточним відрізком).

  res++; temp = v[i++].first; // end

Поки початок наступного відрізка менше кінця поточного, пропускаємо такий відрізок, так як він перетинається з поточним.

  while (i < v.size() && v[i].second < temp) i++;
}

Виводимо відповідь.

printf("%d\n", v.size() - res);