HDU 3415 Max Sum of Max-K-sub-sequence - dp&单调队列优化
分析:
环形要double转换为链状,再跑dp
记dp[i]表示以 i 为结尾的长度不超过k的最大连续子段和
即:
用单调队列优化,O(1)转移。
#include<cstdio>
#include<cstring>
#define MAXN 100000
#define INF 2000000000
struct node{
int val,pos;
}que[MAXN*2+10];
int n,a[MAXN*2+10],sum[MAXN*2+10],dp[MAXN*2+10],L[MAXN*2+10],k;
void Init()
{
memset(sum,0,sizeof sum);
memset(dp,0,sizeof dp);
memset(L,0,sizeof L);
memset(que,0,sizeof que);
}
void read()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
}
n=2*n-1;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
}
void DP()
{
int front=0,rear=1; //que[0].val=0
for(int i=1;i<=n;i++){
while(front<rear){
if(que[front].pos<i-k)
front++;
else
break;
}
dp[i]=sum[i]-que[front].val;
L[i]=que[front].pos+1;
while(front<rear){
if(que[rear-1].val>=sum[i])
rear--;
else
break;
}
que[rear].pos=i,que[rear].val=sum[i];
rear++;
}
int ans1=-INF,ans2=-1,ans3=-1,ans4=-1;
int m=(n+1)/2;
for(int i=1;i<=n;i++){
if(dp[i]>ans1){
ans1=dp[i];
ans2=(L[i]%m)==0?m:(L[i]%m);
ans3=(i%m)==0?m:(i%m);
ans4=i-L[i];
}
else if(dp[i]==ans1){
int t=(L[i]%m==0)?m:(L[i]%m);
if(t<ans2){
ans2=t;
ans3=(i%m==0)?m:(i%m);
ans4=i-L[i];
}
else if(t==ans2){
if(i-L[i]<ans4){
ans3=(i%m)==0?m:(i%m);
ans4=i-L[i];
}
}
}
}
printf("%d %d %d\n",ans1,ans2,ans3);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
Init();
read();
DP();
}
}