Problem - D - Codeforces
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
最近赛中敲不出代码, 赛后倒是镇静了, 我也醉了
简述下思路及变量意义:
这里采取从前到尾遍历,由于数据范围不能完全连乘2e5个的2, 所以我们采取计数方法,
num表示绝对值为2的个数, sign表示当前是正负数, min是从上一个0到现在连乘绝对值最小的负数
带有res的4个变量是截止到1~i的最优方案: res是乘积最大的2的个数, resl是连乘的左边界, resr是连乘的右边界, res0是前面最近所在0的下标+1
解释不清了, 看代码吧
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 2e5+10; LL a[N]; int main() { int t; scanf("%d", &t); while(t --) { int n; scanf("%d", &n); LL sign = 1, num = 0; LL res = 0, minn = -99, resmin = 1, res0 = 1; LL resl=n+1, resr = n; for(int i = 1; i <= n; i ++) { scanf("%lld", &a[i]); //以下四行相当于*a[i], sign表示正负, num表示绝对值=2的个数 if(a[i] == -2) num ++, sign = -1*sign; else if(a[i]==2) num++; else if(a[i]==-1) sign = -1*sign; else if(a[i]==0) num=0; //从头到尾相乘: (数字为0, 下标为res0 - 1) ~ i if(sign>0 && num*sign > res) { res = num*sign; //res 正负表示正负, 大小表示多少个2相乘 resl = res0; //resl:结果左边界 resr = i;//resr:结果右边界 } //中间一段相乘 if(sign<0 && minn!=-99 && minn-num*sign > res) { res = minn-num*sign; resl = resmin; resr = i; } //以下是后面特例的初始化 if(a[i]==0) { res0 = i+1;//前面最近所在0的下标+1 sign=1; minn = -99;//绝对值最小的负数的大小 resmin = i+1;//绝对值最小的负数的下标后一位 } if(sign<0 && num*sign > minn) minn = num*sign, resmin = i+1; } cout << resl-1 << ' '<< n-resr<<'\n'; } return 0; }