邦邦的大合唱站队(状态压缩+前缀和)

108 篇文章 0 订阅

邦邦的大合唱站队

题目背景

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

题目描述

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

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

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

输入格式

第一行2个整数N,M。

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

输出格式

一个整数,表示答案

样例 #1

样例输入 #1

12 4
1
3
2
4
2
1
2
3
1
1
3
4

样例输出 #1

7

提示

【样例解释】

1  33  3
2  34  4
2  41  22  2
3  21  1
1  1
3  14  1

【数据规模】

对于20%的数据, N ≤ 20 , M = 2 N\le 20, M=2 N20,M=2

对于40%的数据, N ≤ 100 , M ≤ 4 N\le 100, M\le 4 N100,M4

对于70%的数据, N ≤ 2000 , M ≤ 10 N\le 2000, M\le 10 N2000,M10

对于全部数据, 1 ≤ N ≤ 1 0 5 , M ≤ 20 1\le N\le 10^5, M\le 20 1N105,M20

思路+代码

由于 M M M 很小,也就是乐队数很少,因此我们可以考虑状态压缩,怎么压缩呢?就是乐队的排序的所有情况进行枚举即可。

状态方程: f [ i ] = m i n { f [ i   x o r   2 j ] + n u m [ j ] − l e n t h [ x , y ] [ j ] } f[i]=min\{f[i \ xor \ 2^j]+num[j] -lenth[x,y][j]\} f[i]=min{f[i xor 2j]+num[j]lenth[x,y][j]}

n u m [ j ] num[j] num[j]代表团队 j j j的总人数, l e n t h [ x , y ] lenth[x,y] lenth[x,y]代表在区间 [ x , y ] [x,y] [x,y]中团队 j j j的总人数。

那么代码就很好写了:


//枚举所有乐队的排列

//f[1101] 表示1/2/4占满前面

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1<<22,M = 1e5+10;

int f[N];
int n,k;
int s[M][21];
int w[M],num[M];//num 表示团队总人数

int main(){
    cin>>n>>k;
    
    for(int i=1;i<=n;i++)cin>>w[i];
    
    for(int i=1;i<=n;i++){
        num[w[i]]++;
        for(int j=1;j<=k;j++)s[i][j]=s[i-1][j];
        s[i][w[i]]++;
    }
    
    memset(f,0x3f,sizeof f);
    
    f[0]=0;
    
    for(int i=1;i<(1<<k);i++){
        int length=0;
        for(int j=1;j<=k;j++)if(i>>(j-1)&1)length+=num[j];
        for(int j=1;j<=k;j++){
            if(i>>(j-1)&1){
                f[i]=min(f[i],f[i^(1<<(j-1))]+num[j]-s[length][j]+s[length-num[j]][j]);
            }
        }
    }
    
    cout<<f[(1<<k)-1];
    
    return 0;
    //kkk
}
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值