给定一个长度为 n 且不包含 0 的整数序列 a1,a2,…,an。
请你计算以下两值:
使得 al×al+1×…×ar 为负的索引对 (l,r)(l≤r) 的数量。
使得 al×al+1×…×ar 为正的索引对 (l,r)(l≤r) 的数量。
题意很简单,就是用前缀和来进行处理,准确的说这里是前缀积
题目中只问我们,在索引对中的值是负是正所以说本质上这个数是什么是不重要的,我们只需要考虑他们的正负关系。
我们假设以 i i i结尾的区间:(i-1, i),(i - 2, i)… (0, i)
因为我们求出来前缀积了,那么这些区间的正负就是 S i / S k , k < i S_i / S_k,k < i Si/Sk,k<i是正是负
如果 S i S_i Si是正的
也就是问我们从s0到si - 1之间有多少个数是正的,因为Si是正的,与前面任意选取一个来进行组合都能贡献出答案,所以当前的答案就是加上前面统计的,此时Si是正的,这时候正的个数就要加一;如果统计负数的个数本质上这时候选择这个正数也可以对负数的答案做贡献,因为正数不改变符号
如果 S i S_i Si是负的,也大致同理,详情看代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int n;
int main(){
cin >> n;
int x;
int s = 1;
// p是整数,n是负数
ll lp = 1, ln = 0; // lp应当从1开始,因为s0是1,这样能保证更新答案
ll rp = 0, rn = 0;
for(int i = 1; i <= n; i++){
cin >> x;
if(x < 0) s *= -1;
if(s > 0) rn += ln, rp += lp, lp++;
else rp += ln, rn += lp, ln++;
}
cout << rn << " " << rp << endl;
return 0;
}