luogu P3694 邦邦的大合唱站队 |状压DP

题目描述

N个偶像排成一列,他们来自M个不同的乐队。每个团队至少有一个偶像。

现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起。重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意。

请问最少让多少偶像出列?

输入格式

第一行2个整数N,M。

接下来N个行,每行一个整数(a_i(1le a_i le M)),表示队列中第i个偶像的团队编号。

输出格式

一个整数,表示答案


#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int res=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}	
	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();}
	return res*f;
}
const int N=1e5+5,M=(1<<21);
int n,m;
int dp[M],sum[N][21];
signed main(){
	n=read(),m=read();
	for(int i=1,x;i<=n;i++){
		x=read();
		for(int j=1;j<=m;j++)sum[i][j]=sum[i-1][j];
		sum[i][x]++;
	}
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	for(int S=0;S<(1<<m);S++){
		int finish=0;
		for(int j=0;j<m;j++)if((S>>j)&1)finish+=sum[n][j+1];
		for(int j=0;j<m;j++){
			if((S>>j)&1)continue;
			int l=finish,r=l+sum[n][j+1];
			dp[S|(1<<j)]=min(dp[S|(1<<j)],dp[S]+sum[n][j+1]-(sum[r][j+1]-sum[l][j+1]));
		}
	}
	cout<<dp[(1<<m)-1]<<endl;
}
原文地址:https://www.cnblogs.com/naruto-mzx/p/13155652.html