Перестановку генів слід виконати таким чином, щоб однакові гени розташовувалися поруч. При цьому необхідно мінімізувати кількість виконаних операцій.
Кожному натуральному числу a_i поставимо у відповідність відрізок [s_i; e_i], де s_i — позиція, на якій a_i зустрічається вперше, а e_i — позиція, на якій a_i зустрічається в останній раз.
Нехай — найбільше можливе число непересічних відрізків. Це значення можна знайти за допомогою алгоритму "вибору заявок", що означає, що кожен із залишених відрізків перетинається хоча б з одним із обраних. Після цього потрібно виконати описану процедуру над генами, яким ці відрізки відповідають.
Якщо — загальна кількість побудованих відрізків. Тоді відповіддю на задачу буде значення k - res.
Приклад
Для наведеного прикладу відрізки матимуть вигляд (нумерація позицій починається з нуля):
для 1: [0; 4];
для 2: [1; 6];
для 3: [3; 5];
для 4: [7; 7];
для 5: [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);