计算在 O(n) 中具有负积的子数组总数

Count Total Subarrays having NEGATIVE PRODUCT in O(n)

本文关键字:数组 计算      更新时间:2023-10-16

在由整数(负数,正数和零(
组成的数组中,任务是找到乘积为数的子数组的总数

如果我找到所有子数组,然后检查负积,它将进入O(n^2(。

long long n,a[200001],i,neg[200001],j;
long long totalneg=0; //prefix array to store number of negative element
cin>>n;
a[0]=0,neg[0]=0;
for(i=1;i<=n;i++)
{   cin>>a[i];
if(a[i]<0)
neg[i]=neg[i-1]+1;
else
neg[i]=neg[i-1];
}
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
if( (neg[j]-neg[i-1]) %2 !=0 )
totalneg++;
}
}
cout<<totalneg;

那么我如何在O(n(时间内找到它。

从第一个值开始:如果它是负数,则找到其中一个子数组,如果它是正数,则找到一个具有正和的子数组(稍后为零(。

然后让我们考虑下一个值:如果为负/为正,则您找到了另一个这样的子数组。但是,您可以将它们与到目前为止找到的所有子数组组合在一起!

如果您找到了 n p 个正子数组,如果当前值为正,则得到另一个 n p 个正子数组,或者如果当前值为负,则得到另一个 np个负数组,类似于负 nn 个数组的计数,只是你得到新数组的负积为正值和新数组的正积为负值。

特殊值为零:任何子数组中包含的此值都将产生零作为乘积,其他因素是什么已经无关紧要了。因此,您可以在此时停止,将 n n添加到某个总数中,然后重新开始,其中 np和 nn 为零。

考虑了数组中的所有数字后,不要忘记将最新计算的 nn 添加到总和中。

现在剩下的就是将这个算法锻造成代码,留给你......如果您遇到麻烦,请随时提出一个新问题,提供您到目前为止编写的代码。

我解决这个问题的方式如下:

我们只关心数字的符号,因为我们不被要求计算乘法的实际结果,我们可以轻松地将输入转换为 1 和 -1,其中每个分别表示一个正整数和一个负整数,如果给定数组是 {1,-2,3} 现在它是 {1,-1,1}。

现在解决这个问题的关键是使用前缀乘法数组来跟踪答案,因为来自 [ i , j ] 的子数组有一个否定的结果,当且仅当前缀 [i ] * 前缀 [ j ] <0 因此

答案 = #negative_numbers_prefix * #positive_numbers_prefix

C++算法看起来像这样:

int main() {
int n,value;
cin>>n;
int positive=1,negative=0,prefix[n]; 
for (int i=0;i<n;i++){
cin>>value; 
if (value>0){
prefix[i]=1; 
}else{
prefix[i]=-1; 
}
if (i>0){
prefix[i]*=prefix[i-1]; 
}
if (prefix[i]==1){ 
positive++; 
}else{
negative++; 
}
} 
int answer=negative*positive;
cout<<answer<<endl;

}

注意:这个问题可能有一些变体,例如计算正子数组乘法的数量而不是负数在这种情况下,有一个非常方便的公式来计算所有可能的子数组,即 ( N * ( N + 1 ((/2 ( 所以如果你想计算正数,你只需要将负数减去总数:( N * ( N + 1 ( (/2 - 答案

"如果数组包含整数 {-1, 2, -3}。然后它将给出输出 4。但是如果数组包含整数 {-1, 2, -3, 0}。然后它将按照上述解决方案给出输出 6。 我已经通过限制条件删除了错误,我的代码是">

import java.io.*;
public class Main1
{
public static void main(String[] args)throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
while(t-->0){
int n = Integer.parseInt(br.readLine());
float a[] = new float[n];
long arr[] = new long[n];
long pos = 1,neg = 0;
String str[] = br.readLine().trim().split("\s+");
for(int i=0;i<n;i++){
a[i] = Float.parseFloat(str[i]);
}
for(int i=0;i<n;i++) {
if(a[i]==0) {
break;
}
if(a[i]>0){
arr[i] = 1;
}else{
arr[i] = -1;
}
if(i>0){
arr[i] = arr[i]*arr[i-1];
}
if (arr[i]==1){ 
pos++; 
}else{
neg++; 
}
}
long ans = (pos*neg)%1000000007;
System.out.println(ans);
}
}
}