题意:
有 N 部电影,每部电影有不同的放映时常,和若干个放映起始时间。
Bessie 可以在一部电影播放过程中的任何时间进入或退出放映厅。每部电影她最多看1次且她不能在看一部电影的过程中,换到另一个正在播放相同电影的放映厅。
Bessie 能不能从0到L分钟连续不断地观看电影?如果能,计算她最少看几部电影。
(1≤L≤100,000,000,1≤N≤20)
题解:
我们发现N很小,只有20,那就可以考虑状压,发现是电影时间是线性的可以通过转移来得到最长时间,那么可以通过状压DP来完成这道题了。
设dp[i]是状态i的时候能看到的最长时间是多少。
枚举每种状态和每种电影,对于如果要通过这部电影j转移,那么需要找到之前还没看这部电影的状态i^(1<<j),然后新的这部电影j的起始时间≤dp[i^(1<<j)],这个可以通过二分去查找,把这个电影起始时间下标记为pos。
那么转移方程为:
最后通过计算一下每个最长时间超过l的状态有多少个1,更新一下ans就行了。
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#define fs first
#define se second
#define pb push_back
#define cppio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> VI;
const int maxn=1e3+6;
const ll inf=0x3f3f3f3f;
const ll mod=1e9+7;
int dp[1<<21];
int a[maxn];
int b[maxn][maxn];
int c[maxn];
int main(){
int n,l;
scanf("%d%d",&n,&l);
for(int i=0;i<n;i++){
scanf("%d",a+i);
int m;scanf("%d",c+i);
for(int j=0;j<c[i];j++){
scanf("%d",&b[i][j]);
}
}
int ans=inf;
for(int i=0;i<(1<<n);i++){
for(int j=0;j<n;j++){
if((1<<j)&i){
int tmp=i^(1<<j);
int pos=upper_bound(b[j],b[j]+c[j],dp[tmp])-b[j]-1;
if(pos>=0){
dp[i]=max(dp[i],dp[tmp]+a[j]);
}
}
}
int tmp=0;
for(int j=0;j<30;j++){
if(i&(1<<j)) tmp++;
}
if(dp[i]>=l) ans=min(ans,tmp);
}
printf("%d",ans);
return 0;
}


京公网安备 11010502036488号