想不出来…然而contest的时候一大堆人过掉了…qwq
颜色数只有 m = 20 m=20 m=20。我那时的想法,设 f [ S ] f[S] f[S]表示把集合 S S S排到最前面时的最小交换数,将这个集合排前面,无论集合内顺序如何,后面剩余部分的相对顺序不变,所以再算一个 g [ S ] [ i ] g[S][i] g[S][i]表示单独考虑 S S S集合,把 i i i排到最前面的最小交换数。然后一直到比赛结束都想不出怎么算 g g g…
然而 g g g是很好算的…设 P [ i ] [ j ] P[i][j] P[i][j]表示把所有 i i i和 j j j抽出来(相对顺序不变),然后让 j j j全排到 i i i前面的最小交换次数。显然每个 j j j需要的交换次数就是它之前的 i i i的个数, O ( n m ) O(nm) O(nm)就可以求出。然后 g [ S ] [ i ] g[S][i] g[S][i]也好算了,就是 s i g m a ( P [ j ] [ i ] ) , j ∈ S sigma(P[j][i]),j∈S sigma(P[j][i]),j∈S。
总复杂度 O ( 2 m ∗ m 2 + n m ) O(2^m * m^2 + nm) O(2m∗m2+nm)。
const int N=400005;
const int S=20;
const int M=(1<<S)-1;
const LL INF=1000000000000000000LL;
int n;LL f[(1<<S)+5],g[S+5][S+5],p[S+5];
int main( )
{
int i,j,k;LL x,y;
read(n);
for(i=1;i<=n;i++)
{
k=read( )-1;
for(j=0;j<S;j++) if(k!=j) g[k][j]+=p[j];
p[k]++;
}
for(i=1;i<=M;i++)
{
x=INF;
for(j=0;j<S;j++)
if((1<<j)&i)
{
for(y=0,k=0;k<S;k++)
if((1<<k)&i) y+=g[j][k];
x=min(x,f[i^(1<<j)]+y);
}
f[i]=x;
}
cout<<f[M];
return 0;
}