Codeforces G. The Brand New Function(枚举)

题目描述:

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;
}

参考文章

关于优化的解释不对就不放了吧。

转载于:https://www.cnblogs.com/zhanhonhao/p/11346711.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值