【数学结论】51Nod 1674 区间的价值 V2

题面在这里

很容易发现,一个序列的前缀and/or值可分为 log(V)

其中V是序列中元素的最大值

然后这题就很好做了

枚举区间的右端点i,同时维护每一个块的范围和值

显然有and块和or块两种分开维护

那么i往后推一个,其实就是把每个块的值and/or上当前位置,再加上单点i

然后合并相邻且值相等的块

扫一波统计答案即可

示例程序:

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;

const int maxn=100005,tt=1000000007;
int n,topo,topa;
struct data{
    int l,w;
    data () {}
    data (int _l,int _w):l(_l),w(_w) {}
    bool operator==(const data&b)const{
        return w==b.w;
    }
}o[maxn],a[maxn];
void merge(data *a,int &n){
//  n=unique(a+1,a+1+n)-a-1;
    int m=1;
    for (int i=2;i<=n;i++)
     if (a[i].w!=a[i-1].w) a[++m]=a[i];
    n=m;
}
int main(){
    scanf("%d",&n);
    topo=topa=0;int ans=0;
    for (int k=1;k<=n;k++){
        int x;scanf("%d",&x);
        for (int j=1;j<=topa;j++) a[j].w&=x;
        for (int j=1;j<=topo;j++) o[j].w|=x;
        a[++topa]=data(k,x); o[++topo]=data(k,x);
        merge(o,topo);merge(a,topa);
        for (int i=topa,j=topo,lst=k;i&&j;){
            int t=max(a[i].l,o[j].l);
            ans=(ans+(LL)a[i].w*o[j].w%tt*(lst-t+1)%tt)%tt;
            i-=(t==a[i].l);j-=(t==o[j].l);lst=t-1;
        }
    }
    printf("%d",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值