Codeforces 780 D. Maximum Product Strikes Back (模擬)
阿新 • • 發佈:2022-04-01
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; }