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;
    }
  • 相关阅读:
    【源码学习之spark core 1.6.1 standalone模式下的作业提交】
    【源码学习之spark streaming 1.6.1 】
    spark udf 初识初用
    spark 累加历史 + 统计全部 + 行转列
    spark 都用了哪些开源东东
    kafka 官方示例代码--消费者
    104. 二叉树的最大深度
    237. 删除链表中的节点
    Leetcode-167. Two Sum II
    Leetcode-215. Kth Largest Element in an Array
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070874.html
Copyright © 2011-2022 走看看