woc……woc……woc……(重要的事情说三遍)
这题TMD是一道有概率AC的题目!!!(博主980ms卡常过去的……)
首先我们都知道前缀或者后缀的and和or值的变化是log级别的。证明:把每一位的权值转化成二进制,and的值只可能递减,or的值只可能递增。
然后我们可以枚举区间的and的值,移动端点,根据每个区间的or值统计答案。
p.s.Manchery大佬太强啦,只能跪在地上orz,大佬传送门
附上AC代码:
#include <cstdio>
#include <cstring>
#define p 1000000007
using namespace std;
typedef long long ll;
int n,a[100005],vis[31];
ll ans,sum,t;
inline char nc(void){
static char ch[10000],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,10000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(register int &a){
static char c=nc();register int f=1;
for (;c<'0'||c>'9';c=nc()) if (c=='-') f=-1;
for (a=0;c>='0'&&c<='9';a=(a<<3)+(a<<1)+c-'0',c=nc());
a*=f;return;
}
int main(void){
read(n);
for (register int i=1; i<=n; ++i) read(a[i]);
for (register int i=0; i<=30; ++i){
sum=0,t=0;
memset(vis,0,sizeof(vis));
for (register int j=1; j<=n; ++j)
if (a[j]&(1<<i))
for (register int k=0; k<=30; ++k){
if (a[j]&(1<<k)) vis[k]=j;
sum=(sum+(1<<k)*(vis[k]-t))%p;
}
else {
for (register int k=0; k<=30; ++k) vis[k]=j;
t=j;
}
ans=(ans+sum*(1<<i))%p;
}
printf("%lld\n",ans);
return 0;
}