题目背景
BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题。
题目描述
N个偶像排成一列,他们来自M个不同的乐队。每个团队至少有一个偶像。
现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起。重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意。
请问最少让多少偶像出列?
输入格式
第一行2个整数N,M。
接下来N个行,每行一个整数a_i(1\le a_i \le M)ai(1≤ai≤M),表示队列中第i个偶像的团队编号。
输出格式
一个整数,表示答案
输入输出样例
输入 #1复制
12 4 1 3 2 4 2 1 2 3 1 1 3 4
输出 #1复制
7
说明/提示
【样例解释】
1 3 √
3 3
2 3 √
4 4
2 4 √
1 2 √
2 2
3 2 √
1 1
1 1
3 1 √
4 1 √
【数据规模】
对于20%的数据,N\le 20, M=2N≤20,M=2
对于40%的数据,N\le 100, M\le 4N≤100,M≤4
对于70%的数据,N\le 2000, M\le 10N≤2000,M≤10
对于全部数据,1\le N\le 10^5, M\le 201≤N≤105,M≤20
上代码:
#include <iostream>
#include <cstring>
using namespace std;
int n,m,x,f[2000000];
//首先枚举人肯定傻逼TLE,数据范围只能用状压
//设f[i]--> 状态I表示从左往右被标记的乐队已排好;
//f[i]表示状压为I时所出列最少人数。
int s[100010][30],num[30],sm[2000000];
bool d(int s,int x){
return (s&(1<<(x-1)));
}
void dfs(int x,int s,bool b)
{
if (x==m) return;
if (b) sm[s|(1<<x)]=sm[s]+num[x+1],dfs(x+1,s|(1<<x),1),dfs(x+1,s|(1<<x),0);
else dfs(x+1,s,1),dfs(x+1,s,0);
}
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++) {
cin>>x;
for (int j=1;j<=m;j++) s[i][j]=s[i-1][j];
s[i][x]++; num[x]++;
}
dfs(0,0,0); dfs(0,0,1);
memset(f,0x3f,sizeof(f)); f[0]=0;
for (int i=1;i<(1<<m);i++)
{
for (int j=1;j<=m;j++) if (d(i,j)) {
int l=sm[i^(1<<j-1)],r=sm[i];
f[i]=min(f[i],f[i^(1<<(j-1))]+(r-l)-(s[r][j]-s[l][j]));
}
}
cout<<f[(1<<m)-1]<<endl;
return 0;
}