1. 程式人生 > >hdu3415 單調佇列求區間最大和

hdu3415 單調佇列求區間最大和

Problem Description Given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and the right neighbour of A[n] is A[1].
Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuous non-empty sub-sequence which length not exceed K.
Input The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. 
Then T lines follow, each line starts with two integers N , K(1<=N<=100000 , 1<=K<=N), then N integers followed(all the integers are between -1000 and 1000).
Output For each test case, you should output a line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the minimum start position, if still more than one , output the minimum length of them.
Sample Input 4 6 3 6 -1 2 -6 5 -5 6 4 6 -1 2 -6 5 -5 6 3 -1 2 -6 5 -5 6 6 6 -1 -1 -1 -1 -1 -1
Sample Output 7 1 3 7 1 3 7 6 2 -1 1 1
/**
hdu3415 單調佇列
題目大意:給出一個有N個數字(N<=10^5)的環狀序列,讓你求一個和最大的連續子序列。這個連續子序列的長度小於等於K。
分析:因為序列是環狀的,所以可以在序列後面複製前k-1個數字。如果用s[i]來表示複製過後的序列的前i個數的和,那麼任意一個子序列[i..j]的和就等於s[j]-s[i-1]。
對於每一個j,用s[j]減去最小的一個s[i](i>=j-k)就可以得到以j為終點長度不大於k的和最大的序列了。將原問題轉化為這樣一個問題後,就可以用單調佇列解決了。
單調佇列即保持佇列中的元素單調遞增(或遞減)的這樣一個佇列,可以從兩頭刪除,只能從隊尾插入。單調佇列的具體作用在於,由於保持佇列中的元素滿足單調性,
對於上述問題中的每個j,可以用O(1)的時間找到對應的s[i]。(保持佇列中的元素單調遞增的話,隊首元素便是所要的元素了)。
維護方法:對於每個j,我們插入s[j-1]的下標,插入時從隊尾插入。為了保證佇列的單調性,我們從隊尾開始刪除元素,直到隊尾元素對應的值比當前需要插入的s[j-1]小,
就將當前元素下標插入到隊尾。之所以可以將之前的佇列尾部元素全部刪除,是因為它們已經不可能成為最優的元素了,因為當前要插入的元素位置比它們靠前,
對應的值比它們小。我們要找的,是滿足(i>=j-k)的i中最小的s[i]。在插入元素後,從隊首開始,將不符合限制條件(i<j-k)的元素全部刪除,此時佇列一定不為空。(因為剛剛插入了一個一定符合條件的元素)。
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;

const int inf=1e9;
const int N=200002;
int n,k,T,a[N],q[N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        a[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]+=a[i-1];
        }
        for(int i=n+1;i<n+k;i++)
            a[i]=a[n]+a[i-n];
        int m=n+k-1;
        int head=0,tail=0;
        int maxx=-inf;
        int l,r;
        for(int i=1;i<=m;i++)
        {
            while(head<tail&&a[i-1]<a[q[tail-1]])
                tail--;
            q[tail++]=i-1;
            while(head<tail&&i-q[head]>k)
                  head++;
            if(maxx<a[i]-a[q[head]])
            {
                maxx=a[i]-a[q[head]];
                l=q[head]+1;
                r=i>n?i%n:i;
            }
        }
        printf("%d %d %d\n",maxx,l,r);
    }
    return 0;
}


相關推薦

hdu3415 單調佇列區間

Problem Description Given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and

[01字典樹]序列完美度(區間異或值)

函數表 字典 style targe efi cnblogs main code blank https://nanti.jisuanke.com/t/15531 解題關鍵:01字典樹模板,用字典樹保存每個數的二進制表示,從而動態維護區間上的最大異或值,註意添加和刪除都可

POJ 3264 線段樹區間小值

很裸的線段樹,沒有什麼好說的,我把根節點所擁有的左右區間都寫在結構體裡面,這樣傳參的時候比較方便。 POJ不支援萬能頭很不習慣。 #include<iostream> #include<cstdio> using namespace std; const int

樹狀陣列區間單點更新

題目連結:https://cn.vjudge.net/contest/66989#problem/B AC程式碼: #include<iostream> #include<string> #include<cstring> #include<cm

hdu1754 區間更新查詢(單點更新+查詢區間值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 106776  &n

一維到三維的區間

p1173 最大連續和 題目 描述 Description 給定N個數,求這N(1 <=N <= 100,000) 個數的某個連續子序列的累加和,保證這個連續子序列的累加和最大。 輸入格式 Input Format 第一行:一個整數N。(1 <=N <

2795 線段樹點修改,區間

題意 給你一個廣告牌的長度和寬度,和要貼的廣告數。每條廣告的長度為 1 ,輸入n條廣告的高。輸出廣告所在的行數。所有的廣告都靠左貼。 #include<cstdio> #include<algorithm> using namespace std;

2823 Sliding Window (單調佇列求解區間值)

POJ - 2823 Time Limit: 12000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu Descri

線段樹區間值+區間更新+區間求和+lazy標記

馬上就省賽了,線段樹還缺個求區間最大值的板子,百度,Google全都是一個板子,而且還沒有lazy標記,樸素更新,好氣啊 區間最小值也同理 lazy的我只能自己寫 藍瘦香菇 code: #include<stdio.h> #include&

POJ 3264 Balanced Lineup(線段樹—區間值與小值差)

Balanced Lineup Time Limit:5000MS Memory Limit:65536K Total Submissions:41077 Accepted:193

RMQ演算法 快速區間小值

RMQ基本上就是來求區間嘴子問題的 maxsum【i】【j】表示從數字num【】下表i開始的後1<<j個數的最大值minsum為最小值  開始初始化兩個陣列         for(i=1;i<=n;i++)         {             m

poj3264(線段樹區間小值)

簡單題,求區間最大值和最小值 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 1000010 int n,a[N

數組所有區間值減去小值之差的(貝殼筆試題)

min pre clu 時間復雜度 print ide turn scan close 這個題直接暴力求解的話時間復雜度肯定是不行的,所以,我們要計算每個數值的貢獻,對每一個數求他當最小值當了多少次,當最大值當了多少次,最後當最大值的次數乘以這個數值減去當最小值的次數乘以

貪心演算法-區間至少連續k的

題意:對於一個整數n,表示該區間整數的個數,求至少有k個連續的數是該區間中一段的最大和。 n的範圍在1~10^6。k(-1000~1000); 分析:這道題看似有點像樹狀陣列,但要想求出區間至少有k個連續的數的和是最大,恐怕是有點難度,頂多是求某一區間的和。 不過可以沿著這

2823 Sliding Window 區間值 線段樹好慢,能用單調佇列

Sliding WindowTime Limit: 12000MSMemory Limit: 65536KTotal Submissions: 14533Accepted: 4096Case Time Limit: 5000MSDescriptionAn array of s

[華為機試練習題]56.子數組的

== process ack turn 多個 popu 基礎 ace ava 題目 描寫敘述: 輸入一個整形數組。數組中連續的一個或多個整數組成一個子數組,每一個子數組都有一個和。求全部子數組的和的最大值。 接口 Int GetSub

連續子數組的

align div 置0 color 最大的 求解 for 技術分享 分享 一、題目:   這是一道考的爛的不能再爛的題目,但是依然有很多公司樂於將這樣的題目作為筆試或面試題,足見其經典。 問題是這樣的:一個整數數組中的元素有正有負,在該數組中找出一個連續子數組,要求該連

UVALive - 3938 分治,線段樹,動態連續

click typedef %d make pac comment blank eof return UVALive - 3938 題意: 給出一個長度為n的整數序列D,你的任務是對m個詢問作出回答。對於詢問(a,b),需要找到兩個下標x和y,使得a≤x≤y&

演算法 子陣列的 C

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

線性動態規劃 老師寫出一行n 個正整數,要求從中選取若干個,但不能選相鄰的數,使選取數的和最大。如:從13、18、28、45、21中選取18、45和為63,是最大和。起初呈呈覺得很容易,可後來越想越感到棘手。老師提示:第i個數是否選取,可確定前i個數中的最大和。它可由前i-1個數中的