topc PB

MCU_NL

problem

  • 給予一組數組,求最大總和
    • 給予n -> n個數字 0 < n <= 3e5
    • 每個數字都在 -1e9 ~ 1e9 內
  • 兩種操作
    • 將單一區間value * 2,且必須先操作 or 不操作
    • 將多個單點 value * -1 (不能操作在已經*2的區間內)

solve

  • 由於區間乘二必須優先做 假定當前區間為全部範圍

原陣列:[-2, 5, -3, 4, -1]

  • 開始往內縮

[-2, 5, -3, 4] -1

這時會賺 3倍的 -1, 原陣列需*2 在考慮接下來*-1 故為三倍

[-2, 5, -3] 4 -1

這時會虧一個 4 因爲4原本可以*2 但我們一定不會將其*-1

由此方法可以把每個單點的虧跟賺轉成單一的數值

總結:對於負數n 我們的單點數值是 abs(n*3)

對於正數我們的單點數值為 -n

example

a = [-2, 5, -3, 4, -1]

b = [6]

a = [-2, 5, -3, 4, -1]
b = [6, -5]

...

b = [6 -5 9 -4 3]

這時可以抓到 -5 為區間最小

真實的答案為 -5這個位置的原陣列位置 5*2

其餘負數*-1 之總和 20

sum([2, 10, 3, 4, 1])

for(int k=0;k<n;k++){
	if(a[k]>=0)b[k]=-a[k];
	else b[k]=abs(a[k]*3);
}

取區間最小

  • 做成前綴和後sliding window
  • 前綴和:p = [0, 6, 1, 10, 6, 9]
  • setup l, r 區間,並在總和>0時更新左邊界
int l=0, rl=0, rr=-1, mm=INT_MAX;
for(int k=1; k<=n; k++){
    if(p[k]-p[l] > 0){
        l = k;  // 更新左邊界
    }
    else {
        if(p[k]-p[l] < mm){
            mm = p[k] - p[l];  // 更新最小區間總和
            rr = k-1;  // 記錄右邊界 -> 由於是區間和,需要微調位置(對應到原本陣列)
            rl = l;    // 記錄左邊界
        }
    }
}
  • 這時將抓到的區間*2 剩餘的都取abs即為ans

AC code

int32_t main(){
    IO;
    int n;cin>>n;
    int a[n],b[n],ans=0;for(auto&k:a)cin>>k;
    for(int k=0;k<n;k++){
        if(a[k]>=0)b[k]=-a[k];
        else b[k]=abs(a[k]*3);
    }
    vector<int>p(1);
    for(auto&k:b)p.push_back(p.back()+k);
    int l=0,rl=0,rr=-1,r=0,mm=INT_MAX;
    for(int k=1;k<=n;k++){
        if(p[k]-p[l]>0){
            l=k;
        }
        else {
            if(p[k]-p[l]<mm){
                mm=p[k]-p[l];
                rr=k-1;
                rl=l;
            }
        }
    }
    for(int k=0;k<n;k++){
        if(k>=rl&&k<=rr)ans+=a[k]*2;
        else ans+=abs(a[k]);
    }
    cout<<ans;
}

topc PB

By rogerdeng

topc PB

  • 96