【JZOJ3853】【NOIP2014八校联考第2场第2试9.28】帮助Bsny(help)

来源:互联网 发布:安卓阅读软件 编辑:程序博客网 时间:2024/05/18 12:35

Description

Bsny的书架乱成一团了,帮他一下吧!
他的书架上一共有n本书,我们定义混乱值是连续相同高度书本的段数。例如,如果书的高度是30,30,31,31,32,那么混乱值为3;30,32,32,31的混乱值也为3。但是31,32,31,32,31的混乱值为5,这实在是太乱了。
Bsny想尽可能减少混乱值,但他有点累了,所以他决定最多取出k本书,再随意将它们放回到书架上。你能帮助他吗?

Data Constraint

20%的数据:1≤n≤20,k=1。
40%的数据:书的高度不是25就是32,高度种类最多2种。
100%的数据:1≤k≤n≤100,注意所有书本高度在[25,32]。

Solution

看到所有书本高度在[25,32]就下意识想到状态压缩dp。我们设f[i][j][k][l]表示前i段书中选走了j本书,当前前i本书中剩下的最后一本高度为k,前i本书中剩下的数的种类的二进制位l的最小混乱值。那么状态就可以分为两种情况:先将所有高度减去25。
1、第i+1段我不取出。那么就将f[i][j][k][l]——>f[i+1][j][a[i+1]][l|2a[i+1]]
2、第i+1段我取出。那么就有两种可能,假设前面还未取出的书中存在该种书,我就插入到该种书后,即f[i][j][k][l]——>f[i+1][j+num[i+1]][k][l]。假设i+1后面的书中存在该种书,我就插入到该种书后,即f[i][j][k][l]——>f[i+1][j+num[i+1]][k][l]。还有可能你直接把这种书丢到最前面,那么幸存的书中也有了这种书,即f[i][j][k][l]+1——>f[i+1][j+num[i+1]][k][l|2a[i+1]]

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int maxn=105;int n,i,t,m,j,k,l,p,num,q,ans;int a[maxn],f[maxn][maxn][9][260],er[8],b[maxn],c[maxn],d[maxn],bz[maxn];int main(){    freopen("data.in","r",stdin);    scanf("%d%d",&n,&m);    for (i=1;i<=n;i++)        scanf("%d",&a[i]),a[i]-=24;    er[1]=1;    for (i=2;i<=8;i++)        er[i]=er[i-1]*2;    for (i=1;i<=n;i++){        if (a[i]!=a[i-1]) b[++num]=a[i];        c[num]++;    }    for (j=num;j>=1;j--){        if (bz[b[j]]) d[j]++;        bz[b[j]]++;    }    n=num;    memset(f,127,sizeof(f));p=(1<<8)-1;f[0][0][0][0]=0;    for (i=0;i<n;i++)        for (j=0;j<=m;j++)            for (k=0;k<=8;k++)                for (l=0;l<=p;l++){                    if (f[i][j][k][l]>n) continue;                    if (b[i+1]==k) t=0;                    else t=1;                    f[i+1][j][b[i+1]][l|er[b[i+1]]]=min(f[i+1][j][b[i+1]][l|er[b[i+1]]],f[i][j][k][l]+t);                    if (j+c[i+1]>m) continue;                     if (l&er[b[i+1]]) t=0;                    else t=1;                    f[i+1][j+c[i+1]][k][l|er[b[i+1]]]=min(f[i+1][j+c[i+1]][k][l|er[b[i+1]]],f[i][j][k][l]+t);                    if (d[i+1]) f[i+1][j+c[i+1]][k][l]=min(f[i+1][j+c[i+1]][k][l],f[i][j][k][l]);                }    ans=1e9;    for (j=0;j<=m;j++)        for (k=0;k<=8;k++)            for (l=0;l<=p;l++)                ans=min(ans,f[n][j][k][l]);    printf("%d\n",ans);}
2 1
原创粉丝点击