2018年山东冬令营 中国石油 飞扬的小鸟II

5793: 飞扬的小鸟II

时间限制: 1 Sec   内存限制: 128 MB
提交: 97   解决: 22
[ 提交][ 状态][ 讨论版]

题目描述

有n棵大树从左到右排成一排,编号为1到n,每棵有高度hi与疲劳值wi。 有一只鸟儿现在站在最左侧的1号大树上,它想飞到第n棵树上去,但它不 能连续飞行太远,当它在第i棵树上时,只能飞到第i + 1, i + 2,..., i + k棵 树上,并获得对应大树的疲劳值;同时,假如它飞到的那棵树的高度不小 于当前这棵树的高度,那么它会获得额外的d疲劳值。求飞到第n棵树的最 小疲劳值是多少。

输入

第一行三个整数n、k和d,由空格分割,表示树有多少棵,飞行的最大距离,以及额外的疲劳值。 接下来n行,第i行包含两个整数hi和wi,表示第i棵树的高度和疲劳值。

输出

输出一行,表示最小疲劳值。

样例输入

5 2 1
4 3
3 2
5 3
2 1
6 1

样例输出

8

提示

最优策略是1 → 2 → 4 → 5,总疲劳值是3 + 2 + 1 + 1,并在4 → 5时支付额外的1疲劳值。

对于20%的数据,n ≤ 1000;
对于另外40%的数据,d = 0;
对于100%的数据,1 ≤ k < n ≤ 3 ∗ 105, 0 ≤ hi ≤ 109, 0 ≤ wi ≤ 103, d ∈{0, 1}。

来源

2018山东冬令营

正常看这个题目n*k稳得一批可以解,但是1S TL 没脾气

所以只能是考虑分解n或者k里面的一个  n肯定没得分解,k却可以,因为只要分析只要找到当前i-j<=k(i>j)中最小的那个就行,因为你想想没一个数肯定是从前边k个树中疲劳最小的那个过来是最舒服的,疲劳值是最小的,因为d只有0和1两种情况。

如果d==0无论如何肯定是找前K个最小的,如果d=1,当前找的第j是既然是最小的,南无想差肯定是>=1的吧,(如果是同样疲劳度的就按照树的高度进行排序,因为这样可以有效避免用到d这一种情况,也是最小的策略)。

用优先队列保存i-k-1 到 i 之间所有的可能,然后top的肯定是最小的而且高度是最高的那种,如果当前i找的最小的不在k的范围内,就pop找到合适一个为止。

好像这种方式叫做单调队列优化

long long dp[300055];
struct node{
    int hi;//高度 
    int wi;//疲劳值 
}N[300055];
struct Node{
    int index;
    int h;
    int w;
    friend bool operator < (Node a, Node b)
    {
        if(a.w==b.w)
            return a.h<b.h;
        return a.w>b.w;
    }
}; 
priority_queue <Node> pr; 
int main ()
{
    int n,k,d;
    scanf("%d%d%d",&n,&k,&d);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&N[i].hi,&N[i].wi);
    dp[1]=N[1].wi;
    Node a;
    a.h=N[1].hi;
    a.w=N[1].wi;
    a.index=1;
    int i=2;
    pr.push(a);
    while(i<=n)
    {
        a=pr.top();
        if(i-a.index<=k)
        {
            if(N[i].hi > N[a.index].hi)
                dp[i]=dp[a.index]+N[i].wi+d;
            else
                dp[i]=dp[a.index]+N[i].wi;
            a.index=i;
            a.h=N[i].hi;
            a.w=dp[i];
            pr.push(a);
        }
        else
        {
            while(i-a.index>k)
            {
                pr.pop();
                a=pr.top();
            }
            i--;
        }
        i++;
    }
  //  for(int i=1;i<=n;i++)
        printf("%lld\n",dp[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/passer__/article/details/79408241