最大连续子序列和问题
最大连续子序列和问题
分为两种类型:①不限制子序列的长度、②限制子序列的长度
问题一:不限制子序列的长度
题:Max Sum
解法一:贪心法,从前向后遍历序列,统计当前和,若当前和大于已有ans,则更新已有答案;若当前和小于0,则由贪心的思想,令当前和为零从新开始统计
下见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=1e6+5,inf=0x3f3f3f3f,mod=998244353;
ll n;
void solve(){
int c;
cin>>c;
ll t,sum,ans=0,pa,pb,f;
for(int i=1;i<=c;++i){
cin>>n;
f=pa=pb=1;
ans=-1000-5;
sum=0;
for(int j=1;j<=n;++j){
cin>>t;
sum+=t;
if(sum>ans){
ans=sum;
pb=j;
pa=f;
}
if(sum<0){
sum=0;
f=j+1;
}
}
cout<<"Case "<<i<<":\n";
cout<<ans<<' '<<pa<<' '<<pb<<'\n';
if(i<c) cout<<'\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
解法二:动态规划。
用\(dp[i]\)表示以a[i]为结尾的最大子序列和。
则可以得到\(dp[i]\)的计算只有两种情况:
①\(dp[i]\)仅包含一个元素(\(a[i]\))
②\(dp[i]\)包括多个元素,从前面某个\(a[v]\)开始,v<i,到\(a[i]\)结束,即\(dp[i-1]+a[i]\)
则,\(dp[i]=max(dp[i-1]+a[i],a[i])\)
下见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=1e6+5,inf=0x3f3f3f3f,mod=998244353;
ll n;
void solve(){
int c;
cin>>c;
ll t,sum,ans=0,start,end,p;
for(int i=1;i<=c;++i){
cin>>n;
vector<ll> dp(n+5,0);
for(int j=1;j<=n;++j){
cin>>dp[j];
}
ans=-1000-5;
p=start=end=1;
for(int i=1;i<=n;++i){
if(dp[i-1]>=0)
dp[i]+=dp[i-1];
else p=i;
if(dp[i]>ans){
ans=dp[i];
end=i;
start=p;
}
}
cout<<"Case "<<i<<":\n";
cout<<ans<<' '<<start<<' '<<end<<'\n';
if(i<c) cout<<'\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
问题二:限制子序列的长度
题:P1714 切蛋糕
利用DP+优先队列解决问题
下见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=5e5+5,inf=0x3f3f3f3f,mod=998244353;
ll n,m,a[maxm];
deque<ll> q;
void solve(){
cin>>n>>m;
ll ans,sum;
a[0]=0;
for(int i=1;i<=n;++i){
cin>>a[i];
a[i]+=a[i-1];//前缀和
}
ans=a[1];
q.push_back(0);
for(int i=1;i<=n;++i){
while(!q.empty()&&i-q.front()>m){//后面部分没有等号,与上文有别
q.pop_front();//删头
}
if(q.empty()) ans=max(ans,a[i]);
else ans=max(ans,a[i]-a[q.front()]);
while(!q.empty()&&a[q.back()]>a[i]){
q.pop_back();//去尾
}
q.push_back(i);
}
cout<<ans<<'\n';
return ;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
例题
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/17478816.html