您的位置:首页 > 其它

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

2017-01-15 07:22 441 查看

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
[j][k][l]);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: