zoukankan      html  css  js  c++  java
  • 选择数字(动态规划+单调队列)

    选择数字

    题目描述:
    给定一行n个非负整数a[1]..a[n]。现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择。你的任务是使得选出的数字的和最大。
    输入描述:
    第一行两个整数n,k
    以下n行,每行一个整数表示a[i]。
    输出描述:
    输出一个值表示答案。
    样例输入:
    5 2
    1
    2
    3
    4
    5
    样例输出:
    12
    数据范围及提示:
    对于20%的数据,n <= 10
    对于另外20%的数据, k = 1
    对于60%的数据,n <= 1000
    对于100%的数据,1 <= n <= 100000,1 <= k <= n,
    0 <= 数字大小 <= 1,000,000,000
    思路:
    考虑动归,在第i点时,在i-k到i中肯定有一个点j不能选择,即:j为断点。
    所以f[i]=max(f[i],f[j-1]+a[j+1]+a[j+2]……a[i])(i-k<=j<=i)
    所以维护前缀和,然后方程就变成了
    f[i]=max(f[i],f[j-1]+sum[i]-sum[j]) (i-k<=j<=i)
    变形一下变成:f[i]=max(f[i],f[j-1]-sum[j])+sum[i] (i-k<=j<=i)
    发现max里面的值只与j有关,所以可以用单调队列优化转移。

    #include<iostream>
    #include<cstdio>
    #define lon long long
    using namespace std;
    const int maxn=100010;
    lon n,k,a[maxn],s[maxn],f[maxn];
    lon head,tail=1,d[maxn],q[maxn];
    lon que(lon j)
    {
        d[j]=f[j-1]-s[j];
        while(head<=tail&&d[q[tail]]<d[j]) tail--;
        q[++tail]=j;
        while(head<=tail&&q[head]<j-k) head++;
        return d[q[head]];
    }
    int main()
    {
        scanf("%lld%lld",&n,&k);
        for(lon i=1;i<=n;i++)
        scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
        for(lon i=1;i<=n;i++)
        {
            lon t=-10000000000;
            /*for(lon j=i-k;j<=i;j++)
            t=max(t,f[j-1]-s[j]);*/
            f[i]=que(i)+s[i];
        }
        cout<<f[n];
        return 0;
    }
  • 相关阅读:
    MySQL5.6.26升级到MySQL5.7.9实战方案【转】
    bootstrap-markdown编辑器引入
    yii获取当前url和域名
    RabbitMQ消息队列在PHP下的应用
    解决 PHPExcel 长数字串显示为科学计数
    Linux实现https方式访问站点
    layui关闭弹出层
    vscode中iframe的使用
    tomcat运行超时问题解决
    Linux安装solr
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070874.html
Copyright © 2011-2022 走看看