[USACO15JAN]电影移动Moovie Mooving

这个题目花了很多时间。

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);
}



猜你喜欢

转载自blog.csdn.net/lengxuenong/article/details/79152322
今日推荐