绿色通道题解

绿色通道

  • 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

主要思路

  • 二分答案,发怒值\(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=0)+a[i],1<=i<=n+1\)
    • \(d[i]\)表示\(1\)~\(i\)题发怒值不超过\(m\)的最短抄题时间

优化

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

    \(code\)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 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<

你可能感兴趣的:(绿色通道题解)