#状压dp#JZOJ 3853 帮助Bsny From 2020.01.16【NOIP提高组】模拟A 组

题目

一共有\(n\)本书,混乱值是连续相同高度书本的段数。
可以取出\(k\)本书随意放回,问最小混乱值,高度\([25\sim 32]\)


分析

\(f[i][j][k][mask]\)表示前\(i\)本书已经抽出了\(j\)本,前\(i\)本中没被抽出的
书里最后一本书的高度是\(k\)\(mask\)是一个\(0\sim 2^8-1\)的二进制,表示前\(i\)本中没被
抽出的书里高度的存在情况。整体表示前\(i\)本书中没被抽出的书组成的序列的最小混乱度。
然后枚举第\(i\)本书是否被抽出。


代码

#include <cstdio>
#include <cstring>
#define rr register
using namespace std;
const int po[9]={1,2,4,8,16,32,64,128,256}; bool v[101];
int b[101],dp[2][101][11][261],top,c[101],t[101],n,m,a[101];
inline void Min(int &a,int b){if (a>b) a=b;}
signed main(){
    scanf("%d%d",&n,&m);
    for (rr int i=1;i<=n;++i){
        scanf("%d",&a[i]),a[i]-=24;
        if (a[i]!=a[i-1]) b[++top]=a[i];
        ++c[top];
    }
    for (rr int i=top;i;--i){
        if (v[b[i]]) ++t[i];
        v[b[i]]=1;
    }
    memset(dp[0],42,sizeof(dp[0]));
    dp[0][0][0][0]=0;
    for (rr int i=1;i<=top;++i){
        memset(dp[i&1],42,sizeof(dp[i&1]));
        for (rr int j=0;j<=m;++j)
        for (rr int k=0;k<9;++k)
        for (rr int p=0;p<po[8];++p){
            if (dp[(i&1)^1][j][k][p]>n) continue;
            Min(dp[i&1][j][b[i]][p|po[b[i]-1]],dp[(i&1)^1][j][k][p]+(b[i]!=k));//不动
            if (j+c[i]>m) continue;
            Min(dp[i&1][j+c[i]][k][p|po[b[i]-1]],dp[(i&1)^1][j][k][p]+!(p&po[b[i]-1]));//放前面
            if (t[i]) Min(dp[i&1][j+c[i]][k][p],dp[(i&1)^1][j][k][p]);//放后面
        }
    }
    rr int ans=2e9;
    for (rr int i=0;i<=m;++i)
    for (rr int j=0;j<9;++j)
    for (rr int k=0;k<po[8];++k)
        Min(ans,dp[top&1][i][j][k]);
    return !printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/Spare-No-Effort/p/12312095.html