1. 程式人生 > 其它 >Codeforces 780 D. Maximum Product Strikes Back (模擬)

Codeforces 780 D. Maximum Product Strikes Back (模擬)

Codeforces 780 D. Maximum Product Strikes Back (模擬)


題目:

題目大意是給一個數組a[1...n] (-2 <= a[i] <= 2) ,問你從前面刪除幾個數,後面刪除幾個數,最後使得剩下數字的乘積最大。輸出前後分別刪除個數。注意:全部刪除的空陣列被認為乘積和為1。

思路:

在比賽中,我思考了一會腦子直接就想放棄。自己在分析問題的能力上存在問題,需要加強!!這道題首先如果有0,那0肯定不在最後的陣列中,所以我們有一個初步的想法用陣列中的0將陣列劃分成很多份。選擇剩下陣列塊中乘積和最大的留下,其他數全部刪了就行。

這樣原問題就轉變成另一個更具體的問題了,就是在一段沒有0的陣列中如何解題。有一個關鍵點:所有數的乘積要麼是最大值要麼是最小值。所以如果最後總成績為正不用刪除,如果為負我們只要刪除一個負數及其一側的值就行。現在問題更加具體了:刪除左側的第一個負數及其左側值,還是刪除右側第一個負數及其右側值。這裡只需要兩邊都算一次比較一下就行了。

如果以前自己做這類題估計即使看了題解,也要參考別人程式碼才能完成。但是現在確實能力有所上升,能直接自己想出思路,然後完成。唯一遺憾的是在比賽時沒法條理清晰地去思考,總是想著有什麼結論,或者什麼很妙的思路。

有幾點在完成時需要注意:

  • 如果最大情況,就是2^200000的值,顯然不能維護這個,貢獻最後有效答案的其實只有2/-2,我們只需要維護含2的數量即可,再單獨算一下負數數量。
  • 我們可以讓a[n + 1] = 0,這樣即使沒有0進行分割也可以最後進行一個計算。使思路實現不需要單獨再討論一種情況

總體思路:

  • 不遇到0就加進sol向量陣列中,遇到0時,將sol存的是前一個分塊,計算其答案並維護最終左右分別刪除個數的答案resl,resr
  • 遇到0
    • 遍歷sol陣列,統計絕對值分別為1,2個數,統計負數個數
    • 負數個數為為偶數個不需要刪除,直接維護答案,更新下一個分塊首位置:tpl
    • 負數個數為奇數個:
      • 分別考慮左右刪除第一個負數後的答案,和維護答案進行比較更新即可
  • 輸出resl, resr

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<set>
#include<fstream>
using namespace std;
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, int> PLI;
typedef pair<ll, ll> PLL;
const int N = 2e6 + 50;
const int mod = 998244353;
const double Pi = acos(- 1.0);
const ll INF = 1e12;
const int G = 3, Gi = 332748118;
ll qpow(ll a, ll b, ll p) { ll res = 1; while(b){ if(b & 1) res = (res * a) % p; a = (a * a) % p; b >>= 1;} return res % p; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }


int a[N];

void solve(){
    int n; scanf("%d",&n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d",&a[i]);
    }

    int res = 0, resl = n, resr = 0;
    int tpl = 1;
    vector<int> sol;
    a[n + 1] = 0;
    for(int i = 1; i <= n + 1; ++ i){
        if(a[i] == 0){
            int tt = sol.size();
            int fu = 0;
            int sum1 = 0, sum2 = 0;
            int sumlr2 = 0, sumrl2 = 0;
            int flaglr = 0;
            int idxlr = 0, idxrl = 0;
            for(int j = 0; j < tt; ++ j){
                if(abs(sol[j]) == 1) sum1 ++;
                else if(abs(sol[j]) == 2) {
                    sum2 ++;
                    if(!flaglr) sumlr2 ++;
                    sumrl2 ++;
                }
                if(sol[j] < 0) {
                    fu ++;
                    if(!flaglr) {
                        flaglr = 1;
                        idxlr = tpl + j;
                    }
                    if(abs(sol[j]) == 2) sumrl2 = 1;
                    else sumrl2 = 0;
                    idxrl = tpl + j;
                }
            }

            if(fu % 2 == 0){
                if(sum2 > res){
                    res = sum2;
                    resl = max(0, tpl - 1);
                    resr = n - (tpl + tt - 1);
                    tpl = i + 1;
                    sol.clear();
                    continue;
                }
            }
            else{
                if(sumlr2 <= sumrl2){
                    int tp = sum2 - sumlr2;
                    if(tp > res){
                        res = tp;
                        resl = idxlr;
                        resr = n - (tpl + tt - 1);
                        tpl = i + 1;
                        sol.clear();
                        continue;
                    }
                }
                else{
                    int tp = sum2 - sumrl2;
                    if(tp > res){
                        res = tp;
                        resl = max(0, tpl - 1);
                        resr = n - idxrl + 1;
                        tpl = i + 1;
                        sol.clear();
                        continue;
                    }
                }
            }
            sol.clear();
            tpl = i + 1;
        }
        else sol.push_back(a[i]);
    }
    printf("%d %d\n",resl, resr);
}

int main() {
    freopen("temp.in", "r", stdin);
    freopen("temp.out", "w", stdout);
    int T; scanf("%d",&T);
    while(T --) solve();
    return 0;
}