思路
首先,明确两点:
(1)若使得 乘积为负数,相乘序列里面要有奇数个负数,正数个数任意
(2)若使得 乘积为正数,相乘序列里面要有偶数个负数,正数个数任意
我们使用:
fu[i]来表示区间[1,i]内负数的个数
sum[i][0/1] 来表示[1,i]内有几个fu[i]的值是偶数/奇数
若 fu[r]-fu[l-1] 为偶数,则[l,r]内元素的乘积为正数,否则为负数
所以我们枚举右端点r,看在r之前有几个端点可以作为左端点l.
若[1,r]内有偶数个负数,即fu[r]为偶数时:
case 1: 使[l,r]内元素的乘积为正数:fu[l-1] 要为偶数,即看此时[1,i-1]有几个fu[i] 为偶数 --> sum[i-1][0]
case 2: 使[l,r]内元素的乘积为负数:fu[l-1] 要为奇数,即看此时[1,i-1]有几个fu[i] 为奇数 --> sum[i-1][1]
fu[r]为奇数时 同理.
综上,Code 如下:
Code
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
int a[N];
int fu[N]; // fu[i]:1~i 有几个负数
int sum[N][2]; // 1~i 有几个 fu[i]的值是偶数、奇数
int n;
int main(){
cin>>n;
ll res=0,odd=0,even=0;
for(int i=1;i<=n;i++) {
cin>>a[i];
if(a[i]<0) res++;
fu[i]=res;
if(fu[i]%2==0) odd++;
else even++;
sum[i][0]=odd;
sum[i][1]=even;
}
res=0;
ll ans=0; // 注意res 和 ans 使用 ll
for(int i=1;i<=n;i++){
if(fu[i]%2==0) res+=sum[i-1][1],ans+=sum[i-1][0];
else res+=sum[i-1][0],ans+=sum[i-1][1];
}
cout<<res+even<<' '<<ans+odd;
return 0;
}