• [題解](單調隊列dp)【2016noip福建夏令營】探險


    P1917 -- 探险

    时间限制:1000MS      内存限制:131072KB

    题目描述(explore.cpp)

    π+e去遗迹探险,遗迹里有 N 个宝箱,有的装满了珠宝,有的装着废品。

    π+e手上有 n+e的地图,所以他知道每一个宝箱的价值,但是他不喜欢走回头路,所以要按顺序拿这 N 个宝箱中的若干个。

    但是拿宝箱很累的。一开始 π+e的体力是 1, 每得到一个宝箱之后, π+e得到的价值是体力 × 宝箱的价值,之后他的体力就会变为原来的 k倍 (0<k<1)。

    π+e 不喜欢连续放过很多宝箱,所以任意一段长度为 M 的序列中, π+e 一定要取走其中的一个宝箱。

    现在 π+e 想知道他能得到的最大价值和。

    输入格式(explore.in)

    第一行,两个整数 N,M,表示的含义如题目中所述;

    第二行,一个小数 k,表示的含义如题目中所述,最多 4 位小数;

    第三行,N 个整数,第 i 个整数表示第 i个宝箱的价值。

    输出格式(explore.out)

    输出一行,一个实数,表示 π+e 能得到的最大价值和,四舍五入保留两位小数。

    样例输入

    3 2
    0.1
    1 2 3

    样例输出

    2.30

    数据规模与约定

    【样例解释】 取第 2 个和第 3 个宝箱,则价值和为 2×1+3×0.1=2.3

    【数据规模与约定】

    对于 30% 的数据,有 1≤N≤10;

    对于 60% 的数据,有 1≤N≤1000;

    对于 100% 的数据,有 1≤N≤100000,1≤M≤N,0<k<1,-10^9≤所有宝箱的价值 ≤10^9 。

    建议在程序运行过程中使用 double 类型存储数据


     題好像並沒有多難,但是看到以後沒有什麼思路,還是做題太少,抄題解太多

    在某次取完后所有後面的結果都會乘上k,而且和後面取多少個無關,所以逆推,每次取的時候給它乘一個k再加上a[i],

    f[i]=max(f[j]*k+a[i]) (i<j<=i+m)

    用單調隊列維護一個區間最大值即可

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100010;
    int n,m,a[maxn];
    int q[maxn],head=1,tail=0;
    double k,f[maxn];
    
    int main()
    {
        scanf("%d%d%lf",&n,&m,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        
        for(int i=n;i>=1;i--){
            while(head<=tail && q[head]>m+i)head++;
            while(head<=tail && f[q[tail]]<f[i+1])tail--;
            q[++tail]=i+1;
            f[i]=f[q[head]]*k+a[i];
        }
        double ans=-0x7fffffff;
        for(int i=1;i<=m;i++)ans=max(ans,f[i]);
        printf("%.2lf
    ",ans);
    }
  • 相关阅读:
    JavaScript 格式化数字
    浅析C#中单点登录的原理和使用
    从银行转账失败到分布式事务:总结与思考
    计算机网络资料
    阿里巴巴Java开发规约插件p3c详细教程及使用感受
    程序员如何打造属于自己的云笔记服务
    sql server2016里面的json功能
    mac pro 开启三只滑动选中文本
    技术网站
    idea gradle项目导入
  • 原文地址:https://www.cnblogs.com/superminivan/p/10757912.html
Copyright © 2020-2023  润新知