题目描述:
The Brand New Function
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Polycarpus has a sequence, consisting of n non-negative integers: a1, a2, ..., *a**n*.
Let's define function f(l, r) (l, r are integer, 1 ≤ l ≤ r ≤ n) for sequence a as an operation of bitwise OR of all the sequence elements with indexes from l to r. Formally: f(l, r) = *a**l* | al + 1 | ... | ar.
Polycarpus took a piece of paper and wrote out the values of function f(l, r) for all l, r (l, r are integer, 1 ≤ l ≤ r ≤ n). Now he wants to know, how many distinct values he's got in the end.
Help Polycarpus, count the number of distinct values of function f(l, r) for the given sequence a.
Expression x | y means applying the operation of bitwise OR to numbers x and y. This operation exists in all modern programming languages, for example, in language C++ and Java it is marked as "|", in Pascal — as "or".
Input
The first line contains integer n (1 ≤ n ≤ 105) — the number of elements of sequence a. The second line contains n space-separated integers a1, a2, ..., *a**n* (0 ≤ *a**i ≤ 106) — the elements of sequence a*.
Output
Print a single integer — the number of distinct values of function f(l, r) for the given sequence a.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use cin, cout streams or the %I64d specifier.
Examples
Input
Copy
3
1 2 0
Output
Copy
4
Input
Copy
10
1 2 3 4 5 6 1 2 9 10
Output
Copy
11
Note
In the first test case Polycarpus will have 6 numbers written on the paper: f(1, 1) = 1, f(1, 2) = 3, f(1, 3) = 3, f(2, 2) = 2, f(2, 3) = 2, f(3, 3) = 0. There are exactly 4 distinct numbers among them: 0, 1, 2, 3.
思路:
这道题刚开始觉得呀!肯定非常繁。但之后再想就有点想法了。想法来自于一个我之前想到的或的性质,就是一个数或另一个数结果是大于等于这两个数,也就是或起来只能增加或不变。然后又想到了题目让求几种可能的值。想到如果把所有数都或起来,那么得到的就是最大值。其次是每个数单独与自己或还是自己,于是有几个不同的数就可以在结果上先加上几。一看数的大小也就\(10^6\),那么或的最大个数也就是\(1111111\)个。可以用一个数组直接标记已获得了哪些值。最后就是想到二重循环,遍历每一种可能。但这样肯定超时啊。再想想。在胡思乱想想能不能用线性时间求解时想到了一个思路,是这样的:从头开始,进行累计或运算,每次把当前或的值与下一个或会得到的值做个比较,如果出现当前值等于下一次或的值时,我们可以说在这个位置及以前的累计值暂时做完了贡献,为什么是暂时呢?因为后面出现的数有可能还会改变这个值。
优化的思想与上面的原理相似,就是排除贡献做完的情况。我在计算或值时用两个变量,一个初始值是起点的值,另一个初始值为零。如果我在累计或值的时候发现两个或值竟然相等了,说明什么?说明起点的值完全没有起到作用对不对?它的贡献相对于后面是零,也就是说我用不用这个数对到两个值相等的后面位置没影响。那就可以跳出循环继续以下一个数为起点计算之后的或值。
网上关于这个优化的解释是数全为一后或它就是本身之类的,但我觉得好像是错的。因为我按照这种解释把这个优化变了一下形,把\(1111111\)之内二进制全为1的数预处理出来,累计或值过程中遇到这样的数就跳出循环,但在样例下得到的答案并不对。然后仔细想了想应该是上面那种解释。
代码:
#include <iostream>
#include <cstdio>
#define max_n 100005
using namespace std;
int n;
int a[max_n];
int cnt[1111112];
int cou = 0;
inline void read(int& x)
{
x=0;int f=0;char ch=getchar();
while('0'>ch||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
x=f?-x:x;
}
int main()
{
read(n);
for(int i = 0;i<n;i++)
{
read(a[i]);
if(cnt[a[i]]==0)
{
cnt[a[i]]=1;
cou++;
}
}
for(int i = 0;i<n;i++)
{
int last = a[i];
int prime = 0;
for(int j = i+1;j<n;j++)
{
last |= a[j];
if(cnt[last]==0)
{
cnt[last] = 1;
cou++;
}
prime |= a[j];
//cout << "last " << last << endl;
if(last==prime)
{
break;
}
}
}
printf("%d",cou);
return 0;
}
参考文章
关于优化的解释不对就不放了吧。