hdu 3415 Max Sum of Max-K-sub-sequence (单调队列)
hdu 3415 题意:给出n个整数,是一个环(也就是a[n]右边是a[1])求一段长度不超过k的数使得和最大,问最大和是多少并给出这段数的位置。
思路:为了处理环,先把n个数复制一下就好,然后求前缀和sum[i]
由于区间[l,r]的和可以用前缀和表示为sum[r]-sum[l-1]
因此在区间长度小于等于k的前提下,我要求sum[r]-sum[l-1]的最大值,如果我们考虑把端点r固定,那么就是要求[l-1,r-1]中的sum的最小值。
因此我们考虑用单调队列来维护sum[i-k]到sum[i-1]的最小值。
我们的做法是:枚举区间右端点i,同时用单调队列维护i之前的k个数[i-k,i-1]的最小值。
由于要求“If there are more than one result, output the minimum start position, if still more than one , output the minimum length of them.”,因此从后面出队的判断条件是严格的sum[dq.back()]>sum[i-1]
/* ***********************************************
Author :111qqz
Created Time :2016年08月05日 星期五 18时02分36秒
File Name :code/hdu/3415.cpp
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
const int N=2E5+7;
int a[N],sum[N];
int n,k;
int on;
deque<int>dq;
inline bool read(int &num)
{
char in;
bool ISN = false;
in=getchar();
if (in==EOF) return false;
while (in!='-'&&(in<'0'||in>'9')) in=getchar();
if (in=='-') ISN = true,num=0;
else num=in-'0';
while (in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if (ISN) num=-num;
return true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("code/in.txt","r",stdin);
#endif
int T;
//scanf("%d",&T);
read(T);
while (T--)
{
scanf("%d%d",&n,&k);
// read(n);
// read(k);
on = n ;
sum[0] = 0 ;
for ( int i = 1 ; i <= n ; i++){
scanf("%d",&a[i]);
// read(a[i]);
a[i+n] = a[i];
}
n = n+k-1;
for ( int i = 1 ; i <= n ; i++) sum[i] = sum[i-1] + a[i];
// for ( int i = 1 ; i <= n ; i++) cout<<a[i]<<" "; cout<<endl;
// for ( int i = 1 ; i <= n ; i++) cout<<sum[i]<<" "; cout<<endl;
dq.clear();
int ans = -inf;
int l,r;
for ( int i = 1 ; i <= n ; i++) //枚举最后一个元素
{
while (!dq.empty()&&dq.front()<i-k) dq.pop_front(); //仍然是维护k个,不过由于前缀和的性质,当前要入队的元素是i-1。
while (!dq.empty()&&sum[dq.back()]>sum[i-1]) dq.pop_back();
dq.push_back(i-1);
if (sum[i]-sum[dq.front()]>ans)
{
ans = sum[i] - sum[dq.front()];
l = dq.front()+1;
r = i ;
}
}
if (r>on) r%=on;
printf("%d %d %d\n",ans,l,r);
}
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}