(转载请标明作者)
1276: 最大子序列和
时间限制: 1 Sec 内存限制: 64 MB
题目描述
输入一个长度为n的整数序列(A1,A2,…,An),从中找出一段连续的长度不超过M的子序列,使得这个子序列的和最大。例如:
序列1,-3,5,l,-2,3,
当M = 2或3时,S = 5 + 1 = 6;当M = 4时,S = 5 + 1 +(-2)+ 3 = 7。
输入
第1行一个整数n表示序列的长度。第2行n个整数,代表序列的元素。第3行一个整数表示M。
输出
一个整数,即子序列的最大和。保证结果不超过longint范围。
样例输入
6
1 -3 5 1 -2 3
3
样例输出
6
提示
50%的数据:N,M≤1000;
100%的数据:N,M≤20000。
朴素算法O(n^2) //耗时3746ms
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,a[20100],sum,ans,t;
inline int read(){
int x=0,w=0;char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
m=read();
for(int i=1;i<=n;i++){
int k= i+m-1>n?n:i+m-1;
if(!a[i]||!a[k]) continue;
ans=0;
for(int j=i;j<k;j++){
ans+=a[j];
sum=max(sum,ans);
}
}
printf("%lld",sum);
return 0;
}
朴素算法居然A了
单调队列优化 耗时0
#include<iostream>
#include<algorithm>
#include<cctype>
#define ll long long
using namespace std;
const int maxn=2e4+10;
int a[maxn],sum[maxn],q[maxn],n,m,ans;
inline int read(){
int x=0,w=0;char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),sum[i]=sum[i-1]+a[i];
m=read();
int head=1,tail=1;q[1]=0;
for(int i=1;i<=n;i++){
if(head<=tail&&q[head]<i-m) head++;
ans=max(ans,sum[i]-sum[q[head]]);
while(head<=tail&&sum[q[tail]]>=sum[i]) tail--;
q[++tail]=i;
}
printf("%d",ans);
}
单调队列:
dalao:讲解