zoukankan      html  css  js  c++  java
  • hdu 3415"Max Sum of Max-K-sub-sequence"(单调队列)

    传送门

    题意:

      给出一个有 N 个数字([-1000 , 1000],N ≤ 105)的环状序列;

      让你求一个和最大的连续子序列,并记录起始点。

      要求这个连续子序列的长度小于等于K,加和相同的不同区间,输出起点最小的那组答案。

    题解:

      因为序列是环状的,所以可以在序列后面复制一段(或者复制前k - 1个数字)。

      如果用sum[ i ]来表示复制过后的序列的前 i 个数的和;

      那么任意一个子序列[ i..j ]的和就等于s[ j ]-s[ i-1 ]。

      对于每一个 j,用s[ j ]减去最小的一个s[ i ](i ≥ j-k+1)就可以得到以 j 为终点长度不大于k的和最大的序列了。

      将原问题转化为这样一个问题后,就可以用单调队列解决了。

    AC代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<deque>
     4 #include<cstdio>
     5 #include<cstring>
     6 using namespace std;
     7 #define INF 0x3f3f3f3f
     8 #define pii pair<int ,int >
     9 const int maxn=2e5+50;
    10 
    11 int n,k;
    12 int a[maxn];
    13 int sum[maxn];
    14 deque<int >deq;
    15 
    16 void Solve()
    17 {
    18     sum[0]=0;
    19     for(int i=1;i < 2*n;++i)
    20         sum[i]=sum[i-1]+a[i];
    21     while(!deq.empty())
    22         deq.pop_back();
    23     deq.push_back(0);
    24 
    25     int ans=-INF;
    26     int ansL,ansR;
    27     for(int i=1;i < 2*n;++i)
    28     {
    29         while(!deq.empty() && deq.front() < i-k)
    30             deq.pop_front();///维护[i-k,i-k+1,...,i-1]的最小值
    31         int curSum=sum[i]-sum[deq.front()];
    32         if(curSum > ans)
    33         {
    34             ans=curSum;
    35             ansL=deq.front()+1;
    36             ansR=i;
    37         }
    38         while(!deq.empty() && sum[deq.back()] >= sum[i])
    39             deq.pop_back();
    40         deq.push_back(i);
    41     }
    42     if(ansR > n)
    43         ansR -= n;
    44     printf("%d %d %d
    ",ans,ansL,ansR);
    45 }
    46 int main()
    47 {
    48 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    49     int test;
    50     while(~scanf("%d",&test))
    51     {
    52         while(test--)
    53         {
    54             scanf("%d%d",&n,&k);
    55             for(int i=1;i <= n;++i)
    56             {
    57                 scanf("%d",a+i);
    58                 a[n+i]=a[i];
    59             }
    60             Solve();
    61         }
    62     }
    63     return 0;
    64 }
    View Code
  • 相关阅读:
    (笔记)ubuntu中取消文件夹或文件等右下解一把锁的标志的方法
    (笔记)Linux常用命令大全
    (笔记)arm-linux-gcc/ld/objcopy/objdump参数总结
    (笔记)Ubuntu下安装arm-linux-gcc-4.4.3.tar.gz (交叉编译环境)
    (笔记)如何安装Arm-linux-gcc
    java application maven项目打自定义zip包
    几种简单的排序算法(JAVA)
    双色球机选算法java实现
    集合的子集输出(位运算方式)
    集合的子集输出(排列组合)
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10792796.html
Copyright © 2011-2022 走看看