这个题目花了很多时间。
N=20, ,状态2^20,然后c=1000,每次二分查找log(1000),然后时间复杂度到了2*10^8,用lowbound不开优氧气优化就超时啦。
// luogu-judger-enable-o2
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=(1<<21);
int n,l,num;
int ti[21],ci[21],a[21][1009],cb[maxn];
int f[maxn];
long long dp(){
memset(f,-1,sizeof(f));
f[0]=0;
int ans=25;
for(int i=0;i<num;i++){//原来状态
if(f[i]==-1)continue;
if(f[i]>=l)continue;
for(int j=0;j<n;j++){//新增一部电影
int t=(1<<j) ;
if(i&t)continue;
if(f[i]>a[j][ci[j]-1]+ti[j])continue;//不增加时间,没得看
int x=lower_bound(a[j],a[j]+ci[j],f[i])-a[j];
if(x>0&&a[j][x]>f[i])x--;
if(a[j][x]<=f[i]&&f[i]<a[j][x]+ti[j]){
f[i|t]=max(f[i|t],a[j][x]+ti[j]);
if(f[i|t]>=l)ans=min(ans,cb[i]+1);
}
}
}
if(ans==25)ans=-1;
return ans;
}
int main(){
cin>>n>>l;
memset(a,63,sizeof(63));
for(int i=0;i<n;i++){
scanf("%d%d",&ti[i],&ci[i]);
for(int j=0;j<ci[i];j++)
scanf("%d",&a[i][j]);
}
num=(1<<n);
for(int i=0;i<num;i++){
int j=i;
while(j)cb[i]+=(j&1),j=(j>>1);
}
cout<<dp();
}
改成手工二分后,勉强过!
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=(1<<21);
int n,l,num;
int ti[21],ci[21],a[21][1009],cb[maxn];
int f[maxn];
int find(int j,int fi) {
int l=0,r=ci[j]-1,ans=-1;
while(l<=r) {
int mid=(l+r)>>1;
if(a[j][mid]<=fi)ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int dp() {
memset(f,-1,sizeof(f));
f[0]=0;
int ans=25;
for(int i=0; i<num; i++) { //原来状态
if(f[i]==-1)continue;
if(f[i]>=l) {
int j=i;
while(j)cb[i]+=(j&1),j=(j>>1);
ans=min(ans,cb[i]);
continue;
}
for(int j=0; j<n; j++) { //新增一部电影
int t=(1<<j) ;
if(i&t)continue;
if(f[i]>a[j][ci[j]-1]+ti[j])continue;//不增加时间,没得看
int x=find(j,f[i]);
if(x==-1)continue;
if(a[j][x]<=f[i]&&f[i]<a[j][x]+ti[j])
f[i|t]=max(f[i|t],a[j][x]+ti[j]);
}
}
if(ans==25)ans=-1;
return ans;
}
int main() {
scanf("%d%d",&n,&l);
for(int i=0; i<n; i++) {
scanf("%d%d",&ti[i],&ci[i]);
for(int j=0; j<ci[i]; j++)
scanf("%d",&a[i][j]);
}
num=(1<<n);
int tmp=dp();
printf("%d\n",tmp);
}