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

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

从数据范围上看,O(n3)的复杂度还是很优秀的,但是单靠三维转移无法完全把状态全都表示出来,我们要发现到高度的范围是[25,32],也就是只有8种,很容易就想到状态压缩。首先把连续一段合并在一起,设fi,j,k,l,表示当前做到第i块,已经让j本书的位置改变了,没被改变位置的最后一本书的高度是kl是一个二进制数,表示某一种高度的书出现了并且没有被移动位置。
我们大致可以分三种情况讨论,第一种:当前这一块不移动;当前块移动,但是在前面和后面都没有同样高度的书本(被取走视作不存在);第三种当前块移动,但是前面或后面有高度相同。对于每一种情况都转移一次。

Code

var
    f:array[0..101,0..101,0..8,0..256] of longint;
    a:array[0..101,1..2] of longint;
    s:array[0..101] of longint;
    p,bz:array[0..101] of boolean;
    n,m,sum,tot,i,j,k,l,x,ans,allow:longint;
    cas:boolean;
function min(x,y:longint):longint;
begin
    if x<y then exit(x);exit(y);
end;
procedure change(var x,y:longint);
begin
    if x>y then x:=y;
end;
begin
    fillchar(a,sizeof(a),255);
    readln(n,m);
    for i:=1 to n do
    begin
        read(x); x:=x-24;
        if x<>a[sum,1] then
        begin
            inc(sum);a[sum,1]:=x;a[sum,2]:=0;
        end;
        inc(a[sum,2]);
    end;
    n:=sum;
    for i:=n downto 1 do if bz[a[i,1]] then p[i]:=true else bz[a[i,1]]:=true;
    fillchar(f,sizeof(f),$7f);
    allow:=f[0,0,0,0];f[0,0,0,0]:=0;
    for i:=0 to n-1 do
        for j:=0 to m do
            for k:=0 to 8 do
                for l:=0 to 255 do
                if f[i,j,k,l]<>allow then
                begin
                    sum:=f[i,j,k,l];
                    tot:=sum;if k<>a[i+1,1] then inc(tot);
                    change(f[i+1,j,a[i+1,1],l or(1 shl(a[i+1,1]-1))],tot);
                    if j+a[i+1,2]<=m then
                    begin
                        if (l and(1 shl(a[i+1,1]-1)))=(1 shl(a[i+1,1]-1)) then
                           change(f[i+1,j+a[i+1,2],k,l],sum);
                        if p[i+1] then
                           change(f[i+1,j+a[i+1,2],k,l],sum);
                        tot:=sum+1;
                        change(f[i+1,j+a[i+1,2],k,l],tot);
                    end;
                end;
    ans:=maxlongint;
    for j:=0 to m do
        for k:=0 to 8 do
            for l:=0 to 255 do
            ans:=min(ans,f[n,j,k,l]);
    writeln(ans);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值