CF 1660D - Maximum Product Strikes Back

思路参考
Maximum Product Strikes Back

You are given an array a a a consisting of n n n integers. For each i ( 1 ≤ i ≤ n ) i (1≤i≤n) i(1in) the following inequality is true: − 2 ≤ a i ≤ 2 −2≤a_i≤2 2ai2.
You can remove any number (possibly 0 0 0) of elements from the beginning of the array and any number (possibly 0 0 0) of elements from the end of the array. You are allowed to delete the whole array.
You need to answer the question: how many elements should be removed from the beginning of the array, and how many elements should be removed from the end of the array, so that the result will be an array whose product (multiplication) of elements is maximal. If there is more than one way to get an array with the maximum product of elements on it, you are allowed to output any of them.
The product of elements of an empty array (array of length 0 0 0) should be assumed to be 1 1 1.
Input
The first line of input data contains an integer t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1t104) —the number of test cases in the test.
Then the descriptions of the input test cases follow.
The first line of each test case description contains an integer n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^5) n(1n2105) —the length of array a a a.
The next line contains n n n integers a 1 , a 2 , … , a n ( ∣ a i ∣ ≤ 2 ) a_1,a_2,…,a_n (|a_i|≤2) a1,a2,,an(ai2) — elements of array a a a.
It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2⋅10^5 2105.
Output
For each test case, output two non-negative numbers x x x and y ( 0 ≤ x + y ≤ n ) y (0≤x+y≤n) y(0x+yn) — such that the product (multiplication) of the array numbers, after removing x x x elements from the beginning and y y y elements from the end, is maximal.
If there is more than one way to get the maximal product, it is allowed to output any of them. Consider the product of numbers on empty array to be 1 1 1.
Example
input

5
4
1 2 -1 2
3
1 1 -2
5
2 0 -2 2 -1
3
-2 -1 -1
3
-1 -2 -2

output

0 2
3 0
2 0
0 1
1 0

Note
In the first case, the maximal value of the product is 2 2 2. Thus, we can either delete the first three elements (obtain array [ 2 ] [2] [2]), or the last two and one first element (also obtain array [ 2 ] [2] [2]), or the last two elements (obtain array [ 1 , 2 ] [1,2] [1,2]). Thus, in the first case, the answers fit: “ 3 3 3 0 0 0”, or “ 1 1 1 2 2 2”, or “ 0 0 0 2 2 2”.
In the second case, the maximum value of the product is 1 1 1. Then we can remove all elements from the array because the value of the product on the empty array will be 1 1 1. So the answer is “ 3 3 3 0 0 0”, but there are other possible answers.
In the third case, we can remove the first two elements of the array. Then we get the array: [ − 2 , 2 , − 1 ] [−2,2,−1] [2,2,1]. The product of the elements of the resulting array is ( − 2 ) ⋅ 2 ⋅ ( − 1 ) = 4 (−2)⋅2⋅(−1)=4 (2)2(1)=4. This value is the maximum possible value that can be obtained. Thus, for this case the answer is: “ 2 2 2 0 0 0”.

题目大意
数组中只有 − 2 , − 1 , 0 , 1 , 2 -2 , -1, 0, 1, 2 2,1,0,1,2 这五个数.
在一个数组中找到这么一个 x x x y y y, 满足 0 ≤ x + y ≤ n 0≤x+y≤n 0x+yn, 并且使得删去部分数后剩下的数的累积最大(左边删 x x x 个, 右边删 y y y 个).
(题目说明了空数组的累积为 1 1 1 , 且答案不唯一)
解题思路
因为数组全删了, 累积结果为 1 1 1 , 所以我们可以默认数组为全删. 然后影响数组的累积的最大值的其实就是 2 2 2 − 2 -2 2 了, 所以我们可以考虑记录 2 2 2 − 2 -2 2 的个数. 其次就是避免出现负数, 当数组中负数的个数为奇数, 那么累积后的结果就为负数, 负数是比正数小的, 我们就需要减少一个负数来使得累积为正数. 最后就是需要考虑的 0 0 0 的情况, 虽然说它比负数大, 但是我们并不想出现 0 0 0 , 那么我们可以将 0 0 0 作为分界点, 将该数组分成若干数组进行以上操作.
首先处理 0 0 0 的情况, 以 0 0 0 作为分界点, 分成若干个数组后, 在若干个数组中进行以下操作:

  • 判断数组累积的正负性
  • 若该数组累积结果为正, 则记录数组中 2 2 2 − 2 -2 2 的个数, 当比最大值大, 则更新数据
  • 若该数组累积结果为负, 先分别从左右两边减一个负数(把左或右边界缩小的不包含该负数), 然后记录两种情况数组中 2 2 2 − 2 -2 2 的个数, 取两者的最大, 当比最大值大, 则更新数据.

(下面代码中, 我是每找到一个数组就进行以上操作)

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t; cin>>t;
    while(t--)
    {
        int n; cin>>n; int a[n];
        for(int i=0; i<n; i++) cin>>a[i];
        int max2 = 0, ansL = 0, ansR = n; //默认全删
        int l=0, r=0;
        while(r < n)
        {
            int sign = 1; //该数组累积的正负性, 默认为正
            while(r<n && a[r]!=0) //边找右边界, 边记录数组正负性
                if(a[r++] < 0) sign ^= 1;
            if(sign) //数组累积为正
            {
                int cnt2 = 0; //记录数组中 2 和 -2 的个数
                for(int i=l; i<r; i++)
                    if(a[i]==2 || a[i]==-2) cnt2++;
                if(cnt2 > max2) max2 = cnt2, ansL=l, ansR = n - r; //更新数据
            }
            else //数组累积为负, 需要删除一个负数(存在至少一个负数)
            {
                int nl = l, nr = r;
                while(nl < r) //找到删除左边第一个负数的边界
                    if(a[nl++] < 0) break;
                while(nr > l) //找到删除右边第一个负数的边界
                    if(a[--nr] < 0) break;
                int cntL=0, cntR=0;
                for(int i=nl; i<r; i++) //记录删除左边第一个负数后的数组的 2 和 -2 的个数
                    if(a[i]==2 || a[i]==-2) cntL++;
                for(int i=l; i<nr; i++) //记录删除右边第一个负数后的数组的 2 和 -2 的个数
                    if(a[i]==2 || a[i]==-2) cntR++;
                //更新数据
                if(cntL > max2) max2 = cntL, ansL=nl, ansR = n - r;
                if(cntR > max2) max2 = cntR, ansL=l, ansR = n - nr;
            }
            l = ++r;
        }
        printf("%d %d\n", ansL, ansR);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花生ono

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>