E. Marbles
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Monocarp has arranged nn colored marbles in a row. The color of the ii-th marble is aiai. Monocarp likes ordered things, so he wants to rearrange marbles in such a way that all marbles of the same color form a contiguos segment (and there is only one such segment for each color).
In other words, Monocarp wants to rearrange marbles so that, for every color jj, if the leftmost marble of color jj is ll-th in the row, and the rightmost marble of this color has position rr in the row, then every marble from ll to rr has color jj.
To achieve his goal, Monocarp can do the following operation any number of times: choose two neighbouring marbles, and swap them.
You have to calculate the minimum number of operations Monocarp has to perform to rearrange the marbles. Note that the order of segments of marbles having equal color does not matter, it is only required that, for every color, all the marbles of this color form exactly one contiguous segment.
Input
The first line contains one integer nn (2≤n≤4⋅105)(2≤n≤4⋅105) — the number of marbles.
The second line contains an integer sequence a1,a2,…,ana1,a2,…,an (1≤ai≤20)(1≤ai≤20), where aiai is the color of the ii-th marble.
Output
Print the minimum number of operations Monocarp has to perform to achieve his goal.
Examples
input
Copy
7 3 4 2 3 4 2 2
output
Copy
3
input
Copy
5 20 1 14 10 2
output
Copy
0
input
Copy
13 5 5 4 4 3 5 7 6 5 4 4 6 5
output
Copy
21
Note
In the first example three operations are enough. Firstly, Monocarp should swap the third and the fourth marbles, so the sequence of colors is [3,4,3,2,4,2,2][3,4,3,2,4,2,2]. Then Monocarp should swap the second and the third marbles, so the sequence is [3,3,4,2,4,2,2][3,3,4,2,4,2,2]. And finally, Monocarp should swap the fourth and the fifth marbles, so the sequence is [3,3,4,4,2,2,2][3,3,4,4,2,2,2].
In the second example there's no need to perform any operations.
思路:
dp[i]中位为1的表示该颜色已经排好序的最小操作数。
ma[i][j]表示,假设只有i,j两种颜色,把i全放j前面的最小移动数。
转移方程是:当前要排好第j种颜色,就等于把当前已经排好的颜色都拿到第j种前面来。
dp[当前已经排好的颜色+排好j] = min(dp[当前已经排好的颜色]+把排好第j种颜色的操作数,dp[当前已经排好的颜色+排好j] )
AC代码:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn = 1e6+50;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1e9+7;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
ll ma[25][25], dp[(1 << 20) + 7];
vector<int> col[25];
int main()
{
int n;
cin >> n;
int temp;
rep(i, 1, n){
cin >> temp;
col[temp].push_back(i);
}
rep(i, 1, 20){
rep(j, 1, 20){
if(i == j) continue;
for(int k = 0; k < col[i].size(); k++){
int v = col[i][k];
if(col[j].size() == 0 || col[j][0] > v) continue;
int st = 0, en = col[j].size();
while(st != en){
int md = (st+en)/2;
if(col[j][md] < v){
st = md+1;
}
else en = md;
}
ma[i][j] += st;
}
}
}
int len = (1<<20);
rep(i, 1, len-1) dp[i] = LINF;
rep(i, 0, len-1){
rep(j, 1, 20){
if((i&(1<<(j-1))) == 0){
ll res = 0;
rep(k, 1, 20){
if(((1<<(k-1))&i)) res += ma[k][j];
}
dp[i|(1<<(j-1))] = min(dp[i] + res, dp[i|(1<<(j-1))]);
}
}
}
cout << dp[len-1] <<endl;
return 0;
}
/*
3 4 2 3 4 2 2
3 4 3 2 4 2 2
3 3 4 2 4 2 2
3 3 4 4 2 2 2
5 5 4 4 3 5 7 6 5 4 4 6 5
*/