http://codeforces.com/contest/244
题意:
给定n个数的序列,n (1 ≤ n ≤ 105) 定义f[l,r] = a[l]|a[l + 1]|......|a[r]求该序列所有所有的不同的f[i,j]的值的个数;
思路:
这题当时看错了写了个n*logn(n)的算法自以为很好结果一提交WA。很明显算法错了。后来怎么想也没想出什么优化来。思维啊.. 纯暴力是(n^3)
我们可以通过这个循环来优化到O(n^2) f[j]表示j到i这一段取或操作得到的数
for (i = 0; i < n; ++i){
for (j = 0; j < i; ++j){
f[j] = f[j]|a[i];
vt[f[j]] = true;
}
}
悲催的我连这个优化都没想到,不得不说思维啊。
不过这样肯定还是会TLE的。
后来看了一下别人的代码,才明白了。
首先我们取或操作实质是对一个数的二进制位添加1的过程。由于0<= a[i] <= 10^6 所以整体取或操作最大也就是10^6次大约20位。当枚举i是我们枚举i的每一位检查前边的数这一位是否出现,若出现过直接跳出,若没有出现过取或操作判断是否出现过,然后统计个数即可。
时间复杂度应该是O(n*20*20)最后是否乘20我也不是很确定,我个人认为得到最大数也就是将20位里面的每一位都置为1,这样我们如果每次添加一个1,最多添加20次即可得到结果。
个人理解如有错误请指正...
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstring>
#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x) ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)
#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 1000007
using namespace std;
//freopen("din.txt","r",stdin);
int a[M];
bool vt[1<<20];
int main(){
//freopen("din.txt","r",stdin);
int i,j,k;
int n;
while (~scanf("%d",&n)){
CL(vt,false);
int res = 0;
for (i = 0; i < n; ++i){
scanf("%d",&a[i]);
if (!vt[a[i]]){
vt[a[i]] = true;
res++;
}
for (j = 0; j <= 20; ++j){//枚举每一位
if (a[i]&(1<<j)){
int st = a[i];
for (k = i - 1; k >= 0 && !(a[k]&(1<<j)); --k){//查看前边数的数这意味是否是1
st |= a[k];
if (!vt[st]){
vt[st] = true;
res++;
}
}
}
}
vt[a[i]] = true;
}
cout<<res<<endl;
}
return 0;
}