【and or分块】51Nod1674[区间的价值 V2]题解

题目概述

给出一个序列 {An} ,求 ni=1nj=iand(ai,ai+1,,aj)or(ai,aI+1,,aj)

解题报告

要了解裸题的做法,这道题是and or分块的裸题,对于任意一个点 i ,有下面的结论:

  1. 定义 And(i,j)=and(ai,ai+1,,aj) ,对于所有 j ,将 And(i,j) 去重之后只会剩下 log2n 个。

    • 定义 Or(i,j)=or(ai,ai+1,,aj) ,对于所有 j ,将 Or(i,j) 去重之后只会剩下 log2n 个。
    • 由于and(单调递减)和or(单调递增)的单调性,上述结论其实很显然。

      对于 i ,我们维护若干个块 (a,b,len) 表示 And(i,j)=a,Or(i,j)=b 且长度为 len ,那么对于 i1 ,只需要从 i 的块推过来并去重就行了。

      由于只有 2log2n 个块(and块和or块夹在一起所以是 2 <script type="math/tex" id="MathJax-Element-21">2</script> 倍),所以暴力搞就行了。

      示例程序

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      const int maxn=100000,Log=17,MOD=1e9+7;
      typedef long long LL;
      
      int n,a[maxn+5],ans,blk;
      struct data {int a,b,len;};
      data b[2*Log+5];
      
      inline void AMOD(int &x,int tem) {x+=tem;if (x>=MOD) x-=MOD;}
      inline void Work(int ID)
      {
          b[++blk]=(data){a[ID],a[ID],1};
          for (int i=1;i<=blk;i++) b[i].a&=a[ID],b[i].b|=a[ID];
          int now=blk;blk=1;
          for (int i=2;i<=now;i++) if (b[i].a==b[blk].a&&b[i].b==b[blk].b) b[blk].len+=b[i].len; else
          b[++blk]=b[i];
          for (int i=1;i<=blk;i++) AMOD(ans,(LL)b[i].a*b[i].b%MOD*b[i].len%MOD);
      }
      int main()
      {
          freopen("program.in","r",stdin);
          freopen("program.out","w",stdout);
          scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);
          for (int i=n;i>=1;i--) Work(i);
          return printf("%d\n",ans),0;
      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值