【题解】邦邦的大合唱站队

邦邦的大合唱站队

\(\text{Solution:}\)

设计状态 \(f[i]\) 表示在状态\(i\)拼齐的情况下需要的最小出队人数。

那么如果要拼进来一个 \(j\) 那么,就需要把 \(j\) 乐队所有人都拿出来。

但是,处于原本就需要拼的位置的人不用,这部分的人是从 \(statePre\)\(stateNow\) 这段长度的差中区间的 \(j\) 的数目。

可以预处理啥的,于是就可以 \(O(m\cdot 2^m)\) \(DP\) 了。

#include<bits/stdc++.h>
using namespace std;
const int dyx=(1<<30);
int n,m,a[200010];
int f[1<<21],sum[1<<21];
int cnt[21],p[21][200010];
inline int Min(int x,int y){return x<y?x:y;}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;++i)cin>>a[i],cnt[a[i]-1]++;
	for(int i=0;i<m;++i)sum[1<<i]=cnt[i];
	for(int i=1;i<=n;++i){
		for(int j=0;j<m;++j)p[j][i]=p[j][i-1];
		p[a[i]-1][i]++;
	}
	for(int i=0;i<(1<<m);++i)
		for(int j=0;j<m;++j){
			if(i>>j&1)continue;
			sum[i|(1<<j)]=sum[i]+cnt[j];
		}
	f[0]=0;
	for(int i=1;i<(1<<m);++i){
		f[i]=dyx;
		for(int j=0;j<m;++j){
			if(i>>j&1){
				f[i]=Min(f[i],f[i^(1<<j)]+cnt[j]-p[j][sum[i]]+p[j][sum[i]-cnt[j]]);
			}
		}
	}
	printf("%d\n",f[(1<<m)-1]);
	return 0;
}
posted @ 2021-07-12 11:29  Refined_heart  阅读(49)  评论(0编辑  收藏  举报