[暴力 乱搞] 51Nod 1674 算法马拉松19 A 区间的价值 V2

因为每个点向前and 向前or 的后缀值是O(32) 

所以可以暴力分段求和 32n

类似的还有后缀gcd 是O(logV)的


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()) x*=b;
}

const ll P=1000000007;
const int N=100005;

struct abcd{
  int l,r,val;
  abcd(int l=0,int r=0,int val=0):l(l),r(r),val(val) { }
}And[35],Or[35];
int tota,toto;

int n,a[N];
ll ans;


int main(){
  int pnt=0;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); for (int i=1;i<=n;i++) read(a[i]);
  for (int i=1;i<=n;i++){
    
    for (int j=1;j<=tota;j++) And[j].val&=a[i];
    And[++tota]=abcd(i,i,a[i]);
    pnt=0;
    for (int j=1;j<=tota;j++){
      int l=And[j].l;
      while (j+1<=tota && And[j+1].val==And[j].val) j++;
      And[++pnt]=abcd(l,And[j].r,And[j].val);
    }
    tota=pnt;

    for (int j=1;j<=toto;j++) Or[j].val|=a[i];
    Or[++toto]=abcd(i,i,a[i]);
    pnt=0;
    for (int j=1;j<=toto;j++){
      int l=Or[j].l;
      while (j+1<=toto && Or[j+1].val==Or[j].val) j++;
      Or[++pnt]=abcd(l,Or[j].r,Or[j].val);
    }
    toto=pnt;

    int pnt1=1,pnt2=1;
    for (int j=1;j<=i;){
      while (j>And[pnt1].r) pnt1++;
      while (j>Or[pnt2].r) pnt2++;
      int last=min(And[pnt1].r,Or[pnt2].r);
      ans+=(ll)And[pnt1].val*Or[pnt2].val%P*(last-j+1)%P;
      ans%=P;
      j=last+1;
    }
  }
  printf("%lld\n",ans);
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值