P3694 邦邦的大合唱站队

/*
吗 m<=20 状态dp
初始 n个人排成一排 m<=10集合 问如何让最少的人出列 使队伍中 每个集合的人都连续
1.集合不用按编号 只要连续就行
2.只要统计最后不符合的人数就行
--暴力枚举集合排列顺序 -20 
3.只要确定状态 区间[i,i+sum[j]-1]
4.考虑局部最优情况 f[i]:i状态下 0/1 ->k集合排不排 最小代价
若已经选好队伍 不考虑顺序 无论怎么排 都ok 枚举最后一个集合

num[i]:i集合人数 sum[i][j]:前i个中 j 集合有几个人 len可以由选择的状态 这3个都可以通过初始化确定
if(i&(1<<(j-1))) f[i]=min(f[i],f[i^(1<<(j-1))]+num[j]-(sum[len][j]-sum[len-num[j]][j]))
(f[i] :++ 之前就已经更新)

*/
/*

*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int n,m,a[100010],f[(1<<21)+10],num[22],sum[100010][22];

int main()
{
    ios::sync_with_stdio(false);
    memset(f,inf,sizeof(f)); f[0]=0;
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i],num[a[i]]++;
        for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j];
        sum[i][a[i]]++;
    } 
    
    for(int i=1;i<(1<<m);i++)
    {
        int len=0;
        for(int j=1;j<=m;j++){
            if(i&(1<<(j-1))) len+=num[j];
        }
        for(int j=1;j<=m;j++){
            if(i&(1<<(j-1))) f[i]=min(f[i],f[i^(1<<(j-1))]+num[j]-(sum[len][j]-sum[len-num[j]][j]));       
        }
    }
    cout<<f[(1<<m)-1]<<'\n';
    return 0;
}

/*
//20 points
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int n,m,a[22],ans[22],vis[22],cnt[22],res=inf;

void dfs(int dep)
{
    if(dep>=m+1){
        //for(int i=1;i<=m;i++) cout<<ans[i]<<" ";
        //cout<<endl;
        int l=1,tmp=0;
        for(int i=1;i<=m;i++) 
        {
            for(int j=l;j<=l+cnt[ans[i]]-1;j++)
                tmp+=(a[j]!=ans[i]);
            l+=cnt[ans[i]];
        }
        res=min(res,tmp);
        return;
    }
    for(int i=1;i<=m;i++)
    {
        if(vis[i]==0){
            vis[i]=1;
            ans[dep]=i;
            dfs(dep+1);
            ans[dep]=0;
            vis[i]=0;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],cnt[a[i]]++;
    dfs(1);
    cout<<res<<endl;
    return 0;
}
*/

 

posted @ 2023-11-21 05:44  JMXZ  阅读(5)  评论(0)    收藏  举报