给定数组的所有可能子数组的按位或的总和

时间:2018-09-15 16:25:22

标签: python python-3.x bitwise-or

我想找到给定数组所有可能子数组的按位或的总和。

这是我到目前为止所做的:

from operator import ior
from functools import reduce
n = int(input())
a = list(map(int, input().split()))
total = 0
for i in range(1,n+1):
    for j in range(n+1-i):
        total += reduce(ior, a[j:j+i])
print(total)

但是它很慢。我该如何优化呢?

2 个答案:

答案 0 :(得分:0)

由于这个问题来自竞争,所以到目前为止我还没有回答。

代码:

#include <bits/stdc++.h>
using namespace std;
#define size 32
#define INT_SIZE 32
typedef long long int Int; 
typedef unsigned long long int Unt;
// Driver code
int main()
{
    Int n;
    cin>>n;
    Int arr[n];
    for(int i=0;i<n;i++)
        cin>>arr[i];
    int zeros[size];
    for(int i=0;i<size;i++)
        zeros[i]=1;
    unsigned long long int sum=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<size;j++)
        {
            if(!(arr[i] & 1))
                zeros[j]++;
            else
            {
                sum+=(Unt)((Unt)zeros[j]*(Unt)(1<<j)*(Unt)(n-i));
                zeros[j]=1;
            }
            arr[i]>>=1;
        }
    }
    cout<<sum;
    return 0;
}

逻辑:

注意*:这是我的思考过程,这可能不容易理解。抱歉,如果我无法让您理解。

举个例子: 5(数组大小) 1 2 3 4 5(数组)

1 = 1.0

1,2 = 1.0&2.1

1,2,3 = 1.0和2.1 [3.0和3.1不会有用,因为它们已经被1和2占用]

1,2,3,4 = 1.0&2.1&4.2

1,2,3,4,5 = 1.0&2.1&4.2是有用的。

在上面的解释中,X.Y表示数字X中的第Y位用于“或”运算。

对于

2 = 2.1

2,3 = 2.1&3.0 [因为1.0将不可用]

{继续..}

因此,如果您仔细地观察到虽然3.0可用,那么当存在1时就不会使用它。

如果需要使用某个位,则先前数字的相同位应为0。[记住这一点,我们稍后再使用]

我们将创建1个名为零的数组,该数组分别给出每个位置上先前数字的最后一组计数(此句子可能会让您感到困惑,请尝试阅读更多内容,您可能会变得更清楚)。

对于给定的数组,

在1:0 0 0

在2:1 1 0 {1的二进制是001}

在3:2 0 1 {2的二进制是010}

在4:3 0 0 {3的二进制是011}

在5:0 1 1 {4的二进制数是100}

结尾:0 2 0 {5的二进制数是101}

我们在上面所做的是,如果将bit设置为bit,则将其设置为0,否则我们将count相加,以便我们可以分别了解有多少个数字未将bit设置为明智的位置,即3、2之前数字在位置2 ^ 2处没有设置位,1数字在2 ^ 0处没有设置位。

现在,我们只需要根据它们的设置位相乘即可。

如果将其设置为1,则我们将添加(zeros [i] +1)(2 ^ i)(n-i)。

答案 1 :(得分:0)

首先让我们找到在 i 处结束的子数组的按位或的总和。令从1到i的所有数组元素的OR为,第ith个元素为 a [i] ,未在 a [中设置]的位i] ,但在中设置的元素来自某些先前的元素, 让我们在这里举例
1 2 2
在位置3,或= 3,a [i] = 2,或^ a [i] = 1 这意味着如果我们删除某个以i结尾的子数组的1或,则1来自某个先​​前的元素。位0接通的最后位置是 1 。 答案是这样的,

ans = or * i

对于从0到m的所有位,
ans-=(i-lastposition [bit])*(1 << bit); // lastposition []给出该位打开的最后一个索引。
为什么居最后位置?因为在lastposition []之前的索引(此位为开)将不会产生影响,因为由于lastposition []处的该位而使OR相同。

最终答案可以通过求和1 <= i <= n的所有答案来求出。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
ll r, a, sum, pos[30];
int main()
{
   int n;
   cin >> n;
   rep(i,1,n)
  {
      cin >> a;
      r |= a;
      ll ex = r^a;
      ll ans = i*r;
      rep(bit,0,30)
        if(ex & (1 << bit))
            ans -= ((ll)(i - pos[bit])* ((ll)1 << bit));
     sum += ans;
     rep(bit,0,30)
        if(a & (1 << bit))
            pos[bit] = i;
}
   cout << sum << '\n';
}