https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1674
相对51nod1564简单一些 区间与运算之和是单减的 或运算是单增的 并且log1e9次之内就会归为0和2^31-1 这和区间gcd是一个道理的 对每个i找出所有以其为左端点的不同值的区间 rmq维护一下即可
这里代码写的比较挫 没有充分利用rmq的倍增特性 多了一个query的复杂度。。
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+10;
ll dp1[maxn][20],dp2[maxn][20];
ll ary[maxn];
int n;
void init()
{
int i,j;
for(i=1;i<=n;i++) dp1[i][0]=ary[i];
for(j=1;(1<<j)<=n;j++){
for(i=1;i+(1<<j)-1<=n;i++){
dp1[i][j]=dp1[i][j-1]&dp1[i+(1<<(j-1))][j-1];
}
}
for(i=1;i<=n;i++) dp2[i][0]=ary[i];
for(j=1;(1<<j)<=n;j++){
for(i=1;i+(1<<j)-1<=n;i++){
dp2[i][j]=dp2[i][j-1]|dp2[i+(1<<(j-1))][j-1];
}
}
}
ll query(int tp,int l,int r)
{
int len;
len=log2(r-l+1);
if(tp==1) return dp1[l][len]&dp1[r-(1<<len)+1][len];
else return dp2[l][len]|dp2[r-(1<<len)+1][len];
}
ll solve()
{
ll ans,p1,p2,r1,r2;
int i,l,r,m,p,res;
ans=0;
for(i=1;i<=n;i++){
p=i;
while(p<=n){
p1=query(1,i,p),p2=query(2,i,p);
l=1,r=n-p+1;
while(l<=r){
m=(l+r)/2;
if(query(1,i,p+m-1)==p1&&query(2,i,p+m-1)==p2) l=m+1,res=m;
else r=m-1;
}
r1=query(1,i,p+res-1),r2=query(2,i,p+res-1);
ans=(ans+(((r1*r2)%mod)*(ll)(res))%mod)%mod;
p+=res;
}
}
return ans;
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%lld",&ary[i]);
init();
printf("%lld\n",solve());
return 0;
}