题解:CF1359D Yet Another Yet Another Task
由于 $a_i \in [-30,30]$,所以我们可以考虑枚举区间出现的最大值。由于可以只选一张牌,所以最大得分的最小值为 $0$。
那么我们首先枚举 $i \in [1,30]$,表示该段区间的最大值为 $i$,然后内层循环求和,即 sum += a[j]。由于最小值为 $0$,所以 sum = max (sum,0) 可以排除掉区间和为负数的情况。又因为第一重循环中已经限制了最大值,所以当出现 a[j] > i 的情况时,也要将 sum 更新为 $0$。答案的更新显然有 ans = max (ans,sum - i),该语句成立的充分条件是序列中出现了 $i$。只需要再用一个数组记录出现数字的情况即可,注意负数的情况(我就是因为这个错误 $\texttt{RE}$ 了一次 qwq),同时还需要注意该数组在 sum 更新时也要同时更新。
最后来简单看一下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <cstdio> #define ll long long #define INF 0x3f3f3f3f using namespace std;const int MAX = 1e5 + 5 ;const int MOD = 1e7 + 9 ;inline int read () ;int a[MAX],sum,n,ans;bool f[50 ];int main () { n = read (); for (int i = 1 ;i <= n;++i) a[i] = read (); for (int i = 1 ;i <= 30 ;++i) { sum = 0 ; for (int j = 1 ;j <= 30 ;++j) f[j] = 0 ; for (int j = 1 ;j <= n;++j) { sum += a[j]; if (sum < 0 || a[j] > i) sum = 0 ,f[i] = 0 ; else if (a[j] > 0 ) f[a[j]] = 1 ; sum = max (sum,0 ); if (f[i]) ans = max (ans,sum - i); } } printf ("%d\n" ,ans); return 0 ; } inline int read () { int s = 0 ;int f = 1 ; char ch = getchar (); while ((ch < '0' || ch > '9' ) && ch != EOF) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { s = s * 10 + ch - '0' ; ch = getchar (); } return s * f; }
后记。看了别的 $\texttt{dalao}$ 的题解,发现 f[i] 的设置有些多余,因为即使最大值 $i$ 没有出现,那么相当于被多减,答案一定不会最优。