\(m\) 很小,考虑状压。状态 \(S\) 一共有 \(m\) 位,每一位代表当前乐队是否排好(即乐队所有成员都站在一起),并假设所有排好的乐队都站在前面。
\(f[S]\) 表示状态为 \(S\) 时最少移动的偶像数目。不管所有排好的乐队顺序如何,它们的总数是一定的。枚举 \(S\) 状态中的每一个 \(0\),如果将它变成 \(1\) 并接在所有排好的乐队后,需要付出的代价为:所有不在指定区域内的偶像出列,所有在指定区域内不是当前乐队的偶像出列,它们进行互换。可以使用前缀和维护。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, m, cnt, a, sum[26][101000], f[(1 << 20) + 666];
int main()
{
scanf("%d%d", &n, &m);
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; i++)
{
scanf("%d", &a);
for(int j = 1; j <= m; j++) sum[j][i] = sum[j][i - 1];
sum[a][i]++;
}
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for(int i = 0; i <= (1 << m) - 1; i++)
{
cnt = 0;
for(int j = 1; j <= m; j++)
if(i & (1 << (j - 1))) cnt += sum[j][n];
for(int j = 1; j <= m; j++)
if((i & (1 << (j - 1))) == 0)
{
int l = cnt + 1, r = cnt + sum[j][n], len = r - l + 1;
f[i | (1 << (j - 1))] = min(f[i | (1 << (j - 1))], f[i] + len - sum[j][r] + sum[j][l - 1]);
}
}
printf("%d", f[(1 << m) - 1]);
return 0;
}
原文:https://www.cnblogs.com/Andy-park/p/12493932.html