目录:
1.3.27 NC15553.数学考试(线性DP)
NC15553.数学考试(线性DP)
题意:
给一个长度为n的数组,求在数组中求出两个不相交且长度为k的最大子段和
思路:
可以先预处理出一个前缀和sum[i]=a[1]+a[2]+..a[i],方便直接计算任意子段的和
之后定义dp[i]为从1到i中以i为终点的长度为k的最大子段和,所以dp[i]仅在i≥k时有定义
最后我们可以通过循环遍历,不断更新dp[i],并且在i≥2k之后开始记录答案,ans=max(dp[i-k]+sum[i]-sum[i-k],ans)
要注意初始化答案与dp[i]为负无穷
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=2e5+10; typedef long long ll; ll dp[maxn],sum[maxn],a[maxn]; int main() { int t,n,k; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&k); ll ans=-1ll<<60; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); sum[i]=a[i]+sum[i-1]; dp[i]=-1ll<<60; } for(int i=k;i<=n;i++){ dp[i]=max(dp[i-1],sum[i]-sum[i-k]); if(i>=2*k){ ans=max(sum[i]-sum[i-k]+dp[i-k],ans); } } cout<<ans<<endl; } return 0; }