前面做過好幾個最大連續子列的問題,這個題是找兩個已知長度的子列,滿足這兩段的和最大這一條件。核心是動規以及樹狀數組。
先說一下樹狀數組:第一個是sum[i]=sum[i-1]+num[i];以及seq[i]=sum[i+k-1]-sum[i-1];seq[i]表示i到i+k-1的和。
動規:dp[i]=a表示在以第i到n-k+1為起點的長度為k的子列中以a為起點的最大。狀態轉移方程是 若seq[i]>seq[dp[i+1]],dp[i]=i;否則dp[i]=dp[i+1]
還要注意資料範圍,要用long long 存
#include<cstdio>#include<iostream>#include<cstring>#define LL long long#define MAXN 2*100000+10using namespace std;LL n,k,num[MAXN],sum[MAXN],seq[MAXN];int dp[MAXN];int main(){ // freopen("in.txt","r",stdin); cin>>n>>k; for(int i=1; i<=n; i++) { cin>>num[i]; sum[i]=sum[i-1]+num[i]; } for(int i=1; i+k-1<=n; i++) seq[i]=sum[i+k-1]-sum[i-1]; dp[n-k+1]=n-k+1; for(int i=n-k; i>=0; i--) { if(seq[i]>=seq[dp[i+1]]) dp[i]=i; else dp[i]=dp[i+1]; } LL max=0; int ans; for(int i=1; i+k<=n; i++) { LL s=seq[i]+seq[dp[i+k]]; if(s>max) { max=s; ans=i; } } cout<<ans<<" "<<dp[ans+k]<<endl; return 0;}
第二種代碼是合并了第一種代碼的最後兩個for迴圈,i是從n-k迴圈到1的,而每一個seq[temp]都是在當前i值下:起點>=i+k的和最大的子列。
#include<cstdio>#include<iostream>#include<cstring>#define LL long long#define MAXN 2*100000+10using namespace std;LL n,k,num[MAXN],sum[MAXN],seq[MAXN];int dp[MAXN];int main(){ //freopen("in.txt","r",stdin); cin>>n>>k; for(int i=1; i<=n; i++) { cin>>num[i]; sum[i]=sum[i-1]+num[i]; } for(int i=1; i+k-1<=n; i++) seq[i]=sum[i+k-1]-sum[i-1]; int temp=n; LL max=0; int s,e; for(int i=n-k; i>=0; i--) { if(seq[i+k]>=seq[temp]) temp=i+k; if(seq[i]+seq[temp]>=max) { max=seq[i]+seq[temp]; s=i; e=temp; } } cout<<s<<" "<<e<<endl; return 0;}