• 绿色通道题解


    绿色通道

    • Description

    高二数学《绿色通道》总共有n道题目要写(其实是抄),编号1..n,抄每道题所花时间不一样,抄第i题要花a[i]分钟。由于lsz还要准备NOIP,显然不能成天写绿色通道。lsz决定只用不超过t分钟时间抄这个,因此必然有空着的题。每道题要么不写,要么抄完,不能写一半。一段连续的空题称为一个空题段,它的长度就是所包含的题目数。这样应付自然会引起马老师的愤怒。马老师发怒的程度(简称发怒度)等于最长的空题段长度。

    现在,lsz想知道他在这t分钟内写哪些题,才能够尽量降低马老师的发怒度。由于lsz很聪明,你只要告诉他发怒度的数值就可以了,不需输出方案。(快乐融化:那么lsz怎么不自己写程序?lsz:我还在抄别的科目的作业……)

    • Input

    第一行为两个整数n,t,代表共有n道题目,t分钟时间。以下一行,为n个整数,依次为a[1],a[2],... a[n],意义如上所述。

    • Output

    一个整数w,为最低的发怒度。

    • Sample Input 1

    17 11
    6 4 5 2 5 3 4 5 2 3 4 5 2 3 6 3 5

    • Sample Output 1

    3

    • Hint

    分别写第4,6,10,14题,共用时2+3+3+3=11分钟。空题段:1-3(长度为3), 5-5(1), 7-9(3), 11-13(3), 15-17(3)。所以发怒度为3。可以证明,此数据中不存在使得发怒度≤2的作法。数据规模:60%数据 n≤2000,100%数据 0<n≤50000,0<a[i]≤3000,0<t≤100000000

    主要思路

    • 二分答案,发怒值\(d[n+1]\)越大,抄题时间\(t\)越短,用二分枚举发怒值。
      • \(d[n+1]<=t\)时,满足题意,\(r=mid-1\)
      • \(d[n+1]>t\)时 ,不满足题意,\(l=mid+1\)
    • \(DP\),求在该发怒值下,最短抄题时间
      • 状态转移方程 \(d[i]=min\left\{d[j]\right\}(i-m-1<=j<i,j>=0)+a[i],1<=i<=n+1\)
      • \(d[i]\)表示\(1\)~\(i\)题发怒值不超过\(m\)的最短抄题时间

    优化

    • 用单调队列或优先队列优化\(DP\)

    \(code\)

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int Max=50010;
    int n,t;
    int a[Max];
    int f[Max];
    struct node
    {
    	int pos,val;
    	friend bool operator <(node a,node b)
    	{
    		return a.val>b.val;
    	}
    };
    
    bool pd(int m)
    {
    	memset(f,0,sizeof(f));
    	priority_queue<node> Q;
    	Q.push((node){0,0});
    	for(int i=1; i<=n+1; i++)
    	{
    		while(!Q.empty()&&Q.top().pos<=i-m-2)	Q.pop();
    		f[i]=Q.top().val+a[i];
    		Q.push((node){i,f[i]});
    	}
    	return f[n+1]<=t;
    }//优先队列优化
    
    
    bool ok(int w)
    {
            int f[50010],q[50010];
    	int k,l=0,r=0;
    	f[0]=0,q[0]=0;
    	for(int i=1; i<=n+1; i++)
    	{
    		k=f[q[l]]+a[i];
    		while(r>=l&&k<=f[q[r]])	r--;
    		r++;
    		q[r]=i;
    		f[i]=k;
    		if(i-q[l]>w)	l++;
    	}
    	return f[n+1]<=m;
    }//单调队列优化
    
    int solve()
    {
    	int l=0,r=n,mid,ans;
    	while(l<=r)
    	{
    		mid=(l+r)>>1;
    		if(pd(mid))	ans=mid,r=mid-1;
    		else	l=mid+1;
    	}
    	return ans;
    }//二分答案
    
    int main()
    {
    	scanf("%d%d",&n,&t);
    	for(int i=1; i<=n; i++)	scanf("%d",&a[i]);
    	cout<<solve()<<endl;
    	return 0;
    }
    
  • 相关阅读:
    THUSC2019游记
    2019-8-2-WPF-从文件加载字体
    2019-8-2-WPF-从文件加载字体
    2018-8-10-VisualStudio-合并代码文件
    2018-8-10-VisualStudio-合并代码文件
    2018-8-10-UWP-分享用那个图标
    2018-8-10-UWP-分享用那个图标
    2018-8-10-WPF-可获得焦点属性
    2018-8-10-WPF-可获得焦点属性
    2018-8-10-WPF-好看的矢量图标
  • 原文地址:https://www.cnblogs.com/vasairg/p/12195337.html
Copyright © 2020-2023  润新知