BZOJ3886 : [Usaco2015 Jan]Moovie Mooving

f[i]表示用i集合内的电影可以达到的最长时间

f[i]向f[i|(1<<j)]更新,此时的时间为第j部电影在f[i]前的最晚上映时间

先排序一遍离散化后用前缀最大值解决

时间复杂度$O(n2^n)$

 

#include<cstdio>

#include<algorithm>

const int N=20,M=40010;

int n,l,i,j,c,d[N],g[N][M],m,q[M],id[M],t[M],f[1<<N],ans=M;

inline bool cmp(int x,int y){return t[x]<t[y];}

inline void min(int b){if(ans>b)ans=b;}

inline void max(int&a,int b){if(a<b)a=b;}

inline int lower(int x){

  int l=1,r=m,mid,t;

  while(l<=r)if(::t[q[mid=(l+r)>>1]]>=x)r=(t=mid)-1;else l=mid+1;

  return t;

}

int main(){

  for(scanf("%d%d",&n,&l);i<n;i++)for(scanf("%d%d",&d[i],&c);c--;id[++m]=i,t[m]=j,id[++m]=-1,t[m]=j+d[i])scanf("%d",&j);

  for(id[++m]=-1,t[m]=l,id[++m]=-1,i=1;i<=m;i++)q[i]=i;

  for(std::sort(q+1,q+m+1,cmp),l=lower(l),i=1;i<=m;i++)if(~id[i])g[id[i]][lower(t[i])]=lower(t[i]+d[id[i]]);

  for(i=0;i<n;i++)for(j=1;j<=m;j++)if(!g[i][j])g[i][j]=g[i][j-1];

  for(f[i=0]=1;i<(1<<n);i++)if(f[i]){

    if(f[i]>=l){min(__builtin_popcount(i));continue;}

    for(j=0;j<n;j++)if(!(i>>j&1))max(f[i|(1<<j)],g[j][f[i]]);

  }

  return printf("%d",ans<M?ans:-1),0;

}

  

 

你可能感兴趣的:(USACO)