P3694 邦邦的大合唱站队

题目背景

BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题。

题目描述

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

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

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

输入输出格式

输入格式:

第一行2个整数N,M。

接下来N个行,每行一个整数(a_i(1le a_i le 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   √

【数据规模】

对于全部数据,(1le Nle 10^5, Mle 20)


(Mle 20)瞩目
容易联想到状压
然后这道题就做完了

#include<iostream>
#include<cstdio>

using namespace std;

int i,m,n,j,k,a[100001],f[1100001],s[100001][21],e[1100001],d[1100001];

int main()
{
    for(i=0;i<=20;i++) e[1<<i]=i+1; 
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) 
    {
        scanf("%d",&a[i]);
        for(j=1;j<=m;j++) s[i][j]=s[i-1][j];
        s[i][a[i]]=s[i-1][a[i]]+1;
    }
    for(i=1;i<=(1<<m)-1;i++)
    {
        k=i;
        while(k)
        {
            int x=k & -k;
            if(!d[i]) d[i]=d[i-x]+s[n][e[x]];
            f[i]=max(f[i],f[i-x]+s[d[i]][e[x]]-s[d[i-x]][e[x]]);
            k-=x;
        }
    }
    printf("%d",n-f[(1<<m)-1]);
}
原文地址:https://www.cnblogs.com/ZUTTER/p/9885236.html