• 洛谷P3694 邦邦的大合唱站队/签到题


    P3694 邦邦的大合唱站队/签到题

    题目背景

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

    题目描述

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

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

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

    输入输出格式

    输入格式:

    第一行2个整数N,M。

    接下来N个行,每行一个整数a_i(1le a_i le M)ai(1aiM),表示队列中第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%的数据,Nle 20, M=2N20,M=2

    对于40%的数据,Nle 100, Mle 4N100,M4

    对于70%的数据,Nle 2000, Mle 10N2000,M10

    对于全部数据,1le Nle 10^5, Mle 201N105,M20

    #include<cstdio>
    const int N=100005,M=26;
    int a[N],b[M],n,m,s[M],sum[M][N],ans=1<<30;
    bool vis[M];
    void dfs(int i, int tot){
        if(i>n){
            if(tot<ans) ans=tot;
            return;
        }
        if(tot>ans) return;
        for(int j=1;j<=m;j++)
            if(!vis[j]){
                vis[j]=true;
                dfs(i+s[j],tot+s[j]-sum[j][i+s[j]-1]+sum[j][i-1]);
                vis[j]=false;
            }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            s[a[i]]++;
        }
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                sum[i][j]=sum[i][j-1];
                if(a[j]==i) sum[i][j]++;
            } 
        dfs(1,0);
        printf("%d",ans);
    }
    70分 暴力
    /*
        状态压缩,dp[i]表示达到i状态出队的最小人数,sum[i][j]表示前i个人有几个属于j乐队那么枚举一个l,r则有dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+(r-l-(sum[r][j]-sum[l][j]))); 
    */
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,dp[(1<<20)+1],a[100010],sum[100010][21];
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);a[i]--;
            for(int j=0;j<m;j++){
                sum[i][j]=sum[i-1][j];
                if(a[i]==j)sum[i][j]++;
            }
        }
        for(int i=0;i<(1<<m);i++)dp[i]=0x7fffffff;dp[0]=0;
        for(int i=0;i<(1<<m);i++){
            int s=0;
            for(int j=0;j<m;j++)if(i&(1<<j))s+=sum[n][j];
            for(int j=0;j<m;j++){
                if(i&(1<<j))continue;
                int num=sum[n][j];
                int r=s+num,l=s;
                dp[i|(1<<j)]=min(dp[i|(1<<j)],(r-l-(sum[r][j]-sum[l][j])+dp[i]));
            }
        }
        printf("%d",dp[(1<<m)-1]);
    }
    100分 状压dp
  • 相关阅读:
    01背包--小P寻宝记——粗心的基友
    StringIndexOutOfBoundsException
    2014秋C++ 第8周项目 分支程序设计
    【JavaScript】正則表達式
    专业函数画图软件Origin
    设计模式学习–Decorator
    python使用requests模块模拟登陆知乎
    分享几个比较好的站点
    【转载】selenium之 定位以及切换frame(iframe)
    判断Selenium加载完成
  • 原文地址:https://www.cnblogs.com/thmyl/p/7710800.html
Copyright © 2020-2023  润新知