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;
    }
  • 相关阅读:
    实验2四则运算结对
    作业5 四则运算 测试与封装 5.1
    0909我对编译的看法
    P2602 [ZJOI2010]数字计数(递推+数位dp写法)
    模数的世界[数论]
    P2312[秦九韶+读入取模+哈希解方程]
    第三章 Python 的容器: 列表、元组、字典与集合
    第二章 Python 基本元素:数字、字符串、变量
    第一章 Python 之初探
    第四章 Python 外壳 :代码结构
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070874.html
Copyright © 2011-2022 走看看