最大连续子序列和问题

最大连续子序列和问题

分为两种类型:①不限制子序列的长度、②限制子序列的长度

问题一:不限制子序列的长度

题: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;
}

例题

posted on 2023-06-13 22:00  Qiansui  阅读(29)  评论(0编辑  收藏  举报