2019.12.01日常总结

一本通1603

【题意】: 高二数学《绿色通道》总共有 n n 道题目要抄,编号 1 n 1…n ,抄第 i i 题要花 a i a_i 分钟。小Y决定只用不超过 t t 分钟抄这个,因此必然有空着的题。每道题要么不写,要么抄完,不能写一半。下标连续的一些空题称为一个空题段,它的长度就是所包含的题目数。这样应付自然会引起马老师的愤怒,最长的空题段越长,马老师越生气

现在,小Y想知道他在这 t t 分钟内写哪些题,才能够尽量减轻马老师的怒火。由于小Y很聪明,你只要告诉他最长的空题段至少有多长就可以了,不需输出方案。
【思路】: 我们发现这题要维护的量有两个:空题段的长度已花费的时间。如果我们想一次性维护这两个量的话就有一点复杂。
但是题目所求可以抽象成最大值最小,这很容易让我们联想到二分。细细一想,我们可以发现这题的单调性,即可二分性:如果最长空题段的长为 k k 时,可以在 t t 分钟内抄完,那么如果空题段的长 L > k L>k ,也一定可以在 t t 分钟内抄完。
具体地,我们可以二分一个值 m i d mid ,表示最长的空题段的长度不超过 m i d mid ,我们可以用dp求出此时的最小时间。记 f [ i ] f[i] 表示 i i 必抄时的最短时间,则 f [ i ] = m i n { f [ j ] } + a [ i ] f[i]=min\{f[j]\}+a[i] ,其中 i m i d j < i i-mid\leq j<i ,可以用单调队列优化它。
【代码】:

const int N=5e4+100;
int q[N],dp[N],a[N],n,T;
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
	char c=0;int x=0;bool f=0;
	while (!g(c)) f=c=='-',c=gc;
	while (g(c)) x=x*10+c-48,c=gc;
	return f?-x:x;
}
inline bool check(int mid){
	register int h=1,t=1;
	for(int i=1;i<=n;i++){
		while (h<=t&&q[h]<i-mid-1) h++;
		dp[i]=dp[q[h]]+a[i];
		while (h<=t&&dp[i]<dp[q[t]]) t--;
		q[++t]=i;
	}
	register int ans=dp[n-mid];
	for(int i=n-mid+1;i<=n;i++)
		ans=min(ans,dp[i]);
	return ans<=T;
}
int l,r,mid,ans;
int main(){
//	freopen("t1.in","r",stdin);
	n=read();T=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	l=0;r=n;
	while (l<=r){
		mid=(l+r)>>1;
		if (check(mid)){
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	printf("%d",ans);
	return 0;
}

【时间复杂度】: O ( N × l o g N ) O(N \times logN)

发布了82 篇原创文章 · 获赞 4 · 访问量 1782

猜你喜欢

转载自blog.csdn.net/ZHUYINGYE_123456/article/details/103334309