《Tzoj-3927》dp思路

【《Tzoj-3927》dp思路】题意:给你一个环形序列,让你求最大连续子序列和.
解法:环形的最大连续子序列和问题
一开始我的思路是化环为链,然后去dp,但是这样就不能保证有没有重复。
如果要保证没有重复。
那就需要去枚举长度,这样时间复杂度就会升到n^2。
正解思路:
首先这个子序列肯定分为两种情况:
1.跨过了首尾.
2.没有跨过首尾.
对于2我们只需要传统的dp就行了.即普通地求最大连续子序列和
对于1这种情况,我们可以求得最小的连续子序列,这样我们用序列总和减去它,那就是最大的了.
如果求最小的连续子序列:我们可以先将序列的每个数取反,然后就变成了求最大连续子序列。
然后用总的去减去这个和的相反数(其实就是加上这个和)
对于这两种情况我们比较下哪个更大,然后输出.
需要注意的是,当这个序列全是负数时,我们第二种情况会是最小的负数,但是第一种情况我们计算出来会是0.
所以我们需要在输入后判断是不是全是负数,如果全是负数,我们就不考虑第一种情况了.(注意数据会爆longlong)

LL a[N],dp[N]; int main() { int t,n; sd(t); while(t--) { LL sum = 0; int cnt = 0; sd(n); for(int i=0; i<=n; ++i) dp[i] = 0; for(int i=1; i<=n; ++i) { sld(a[i]),sum += a[i]; if(a[i] < 0) cnt++; } LL ans = -INF; for(int i=1; i<=n; ++i) { dp[i] = max(dp[i-1],LL(0))+a[i]; ans = max(ans,dp[i]); a[i] = -a[i]; } if(cnt == n) { plr(ans); continue; } LL temp = -INF; for(int i=0; i<=n; ++i) dp[i] = 0; for(int i=1; i<=n; ++i) dp[i] = max(dp[i-1],LL(0))+a[i],temp = max(temp,dp[i]); LL t = sum+temp; printf("%lld\n",ans>=t?ans:t); } system("pause"); return 0; }

    推荐阅读