「POI2010」积木 Blocks

单调栈

可以发现子序列的平均数不小于k就可以使子序列的每个数都不小于k

将每个数减去k,则子序列之和非负即可

记 si = a1 + a2 +....+ ai - k*i

考虑序列的两个端点 l, r

对于 l: l1 < l2 && sl1 <=  sl2, 则l1 比 l2 优

对于 r:   r1 < r2 && sr1 <= sr2 则r2 比 r1 优

从0到n 将可能最优 l 加入单调栈中,可以发现栈是单调递增的

从n到1 的可能最优 r 的是单调递减的

每次将当前栈中满足sr - sl ≥ 0的 l 都弹出,最后一个被弹出的就是最优的l

而且对与更小的 r,它的值会更大,所以被弹出的l更不会用到

 1 #include 
 2 using namespace std;
 3 
 4 const int N = 1e6 + 5;
 5 typedef long long LL;
 6 
 7 int n, m, a[N], k, ans, zhan[N], top;
 8 LL s[N];
 9 
10 void Solve() {
11     ans = top = 0;
12     zhan[++top] = 0;
13     for (int i = 1; i <= n; i++) {
14         s[i] = s[i - 1] + a[i] - k;
15         if (s[i] < s[zhan[top]])
16             zhan[++top] = i;
17     }
18     for (int i = n; i; i--) {
19         while (s[i] - s[zhan[top]] >= 0 && top) top--;
20         ans = max(ans, i - zhan[top + 1]);
21     }
22     cout << ans << " ";
23 }
24 
25 int main() {
26     cin >> n >> m;
27     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
28     for (int i = 1; i <= m; i++) {
29         scanf("%d", &k);
30         Solve();
31     }
32     return 0;
33 }
View Code

 

你可能感兴趣的:(「POI2010」积木 Blocks)