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

来源:互联网 发布:js单独一个文件怎么写 编辑:程序博客网 时间:2024/04/30 04:29

题面在这里

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

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

然后这题就很好做了

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

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

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

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

扫一波统计答案即可

示例程序:

#include<cstdio>#include<algorithm>#define LL long longusing 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;}
原创粉丝点击