bzoj3886 [Usaco2015 Jan]Moovie Mooving 状压dp+二分

37 篇文章 0 订阅
21 篇文章 0 订阅

Description


Bessie is out at the movies. Being mischievous as always, she has decided to hide from Farmer John for L (1 <= L <= 100,000,000) minutes, during which time she wants to watch movies continuously. She has N (1 <= N <= 20) movies to choose from, each of which has a certain duration and a set of showtimes during the day. Bessie may enter and exit a movie at any time during one if its showtimes, but she does not want to ever visit the same movie twice, and she cannot switch to another showtime of the same movie that overlaps the current showtime. Help Bessie by determining if it is possible for her to achieve her goal of watching movies continuously from time 0 through time L. If it is, determine the minimum number of movies she needs to see to achieve this goal (Bessie gets confused with plot lines if she watches too many movies).

PoPoQQQ要在电影院里呆L(L<=10^9)分钟,这段时间他要看小型电影度过。电影一共N(N<=20)部,每部都播放于C(C<=1000)段可能重叠的区间,PoPoQQQ决不会看同一部电影两次。现在问他要看最少几部电影才能度过这段时间? 注:必须看电影才能在电影院里呆着,同时一场电影可以在其播放区间内任意时间入场出场。

Solution


这又是一道sb题练习stl
lower_bound(st,ed,x)是找到第一个大于等于x的数字
upper_bound(st,ed,x)是找到第一个小于等于x的数字
它们俩的意义和名字好像是反的囧

看到n很小考虑状压。f[i]表示状态为i时最久能看多久,然后我们枚举转移即可
考虑到直接枚举播放的区间会T,我们二分这个区间。可以证明左端点不超过f[i]且最靠右的区间最优秀

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st,_=ed;i<=_;++i)
#define lowbit(x) ((x)&(-(x)))

const int INF=0x3f3f3f3f;
const int N=1005;

int f[1048577],v[1048577],st[21][N],len[21];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

int count(int x) { int ret=0;
    for (;x;x-=lowbit(x)) ret++;
    return ret;
}

int max(const int &x,const int &y) {
    return x>y?x:y;
}

int main(void) {
    int n=read(),l=read(),ans=INF;
    rep(i,1,n) {
        len[i]=read(); st[i][0]=read();
        rep(j,1,st[i][0]) st[i][j]=read();
    } int cnt,k,tar;
    rep(i,0,(1<<n)-1) {
        cnt=count(i);
        rep(j,1,n) if (!((1<<j-1)&i)) {
            k=std:: upper_bound(st[j]+1,st[j]+st[j][0]+1,f[i])-st[j]-1;
            if (k&&st[j][k]<=f[i]) {
                tar=i|(1<<j-1);
                f[tar]=max(f[tar],st[j][k]+len[j]);
            }
        }
        if (f[i]>=l) ans=cnt<ans?cnt:ans;
    }
    if (ans==INF) ans=-1;
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值