我想找到给定数组所有可能子数组的按位或的总和。
这是我到目前为止所做的:
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)
但是它很慢。我该如何优化呢?
答案 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';
}