51nod 1674 区间的价值V2(思维+拆位+尺取法)

最近被四区题暴虐。。。

题意:lyk拥有一个区间。

它规定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积。

例如3个数2,3,6。它们and起来的值为2,or起来的值为7,这个区间对答案的贡献为2*7=14。

现在lyk有一个n个数的序列,它想知道所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果是多少。

区间的and值和区间的or值相乘,实际上等于将and值分解为2的幂次和的形式与or值分解成2的幂次和的形式相乘。

所以对于同一段区间来说,是可以按位来统计的。

首先将数列按位分解成32个位数列。

枚举区间的左端点,,区间的and值要对答案有贡献必须为1,随着右端点右移,and值为不递增的,而区间的or值要对答案有贡献必须为1,随着右端点右移,or值为不递减的。

找到这两个满足条件的最大区间的交集,即可统计出这段区间对答案的贡献。

先用尺取法进行预处理,再依此统计答案。

时间复杂度O(n*loga*loga)。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-8
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
    int x=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1; ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
inline void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}
const int N=100005;
//Code begin...

int R[32][N], L[32][N], n, mod[65];
LL ans;
bool wei[32][N];

void init(){
    mod[0]=1; FOR(i,1,64) mod[i]=(mod[i-1]<<1)%MOD;
    FO(i,0,32) {
        int l=1, r=1;
        while (l<=n) {
            if (!wei[i][l]) L[i][l]=0;
            else {
                r=max(r,l);
                while (r<n&&wei[i][r+1]) ++r;
                L[i][l]=r;
            }
            ++l;
        }
    }
    FO(i,0,32) {
        int l=1, r=1;
        while (l<=n) {
            if (wei[i][l]) R[i][l]=l;
            else {
                r=max(l,r);
                while (r<=n&&!wei[i][r]) ++r;
                R[i][l]=r;
            }
            ++l;
        }
    }
}
void sol(){
    FO(i,0,32) FOR(j,1,n) {
        if (!wei[i][j]) continue;
        FO(k,0,32) {
            if (R[k][j]>L[i][j]) continue;
            ans=(ans+(LL)(L[i][j]-R[k][j]+1)*mod[i+k])%MOD;
        }
    }
}
int main ()
{
    int x;
    n=Scan();
    FOR(i,1,n) {
        x=Scan();
        FO(j,0,32) wei[j][i]=x%2, x/=2;
    }
    init();
    sol();
    printf("%lld\n",ans);
    return 0;
}

时间: 2025-01-02 17:34:20

51nod 1674 区间的价值V2(思维+拆位+尺取法)的相关文章

1674 区间的价值 V2(分治)

1674 区间的价值 V2 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 lyk拥有一个区间. 它规定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积. 例如3个数2,3,6.它们and起来的值为2,or起来的值为7,这个区间对答案的贡献为2*7=14. 现在lyk有一个n个数的序列,它想知道所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果是多少. 例如当这个序列为{3,4,5}时,那么区间[1,1],

hihocoder-1483区间价值 (二分+尺取法)

题目链接: 区间价值 给定n个数A1...An,小Ho想了解AL..AR中有多少对元素值相同.小Ho把这个数目定义为区间[L,R]的价值,用v[L,R]表示. 例如1 1 1 2 2这五个数所组成的区间的价值为4. 现在小Ho想知道在所有的的v[L,R](1 <= L <= R <= n)中,第k小的值是多少. Input 第一行一个数T(T<=10),表示数据组数. 对于每一组数据: 第一行两个数n,k(1<=n<=200,000,1<=k<=n*(n+1

【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和

题意:给出N个数,M个操作.操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和.n,m<=100000,ai<=1000 题解: 当年(其实也就是今年)做不出来的题..D1T1啊... 因为ai<=1000,我们可以拆位处理.拆成10个二进制位,每位开1棵线段树. 对于每个节点,维护: d:这段区间的异或和 L[0],L[1]:子区间一定从左端点开始,异或和为0,1的子区间分别有多少个 R[0],R[1]:子区间一定从右端点开始,异或和为0,1的

hdu 5696 区间的价值 单调栈+rmq

区间的价值 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1). 现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少. 当然,由于这个问题过于简单. 我们肯定得加强一下. 我们想要知道的是,对于长度为1∼n

区间的价值(线段树)百度之星

区间的价值 Accepts: 0 Submissions: 0 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在LLL,右端点在RRR,那么该区间的长度为(R−L+1)(R-L+1)(R−L+1). 现在聪明的杰西想要知道,对于长度为kkk的区间,最大价值的区间价值是多少.

HDU 5696 ——区间的价值——————【线段树、快排思想】

区间的价值 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 662    Accepted Submission(s): 329 Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1). 现在聪明的杰西想要知道,对于长度为k的区间,最大

hdu5696区间的价值 -- 2016&quot;百度之星&quot; - 初赛(Astar Round2B)

Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1). 现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少. 当然,由于这个问题过于简单. 我们肯定得加强一下. 我们想要知道的是,对于长度为1∼n的区间,最大价值的区间价值分别是多少. 样例解释: 长度为1的最优区间为2−2 答案为6∗6 长度为2的最优区间为4−5 答案为4∗4 长度为3的最优区间为2−4 答案为2∗6 长度

[hdu] 5696 区间的价值 || 序列分治

原题 我们定义"区间的价值"为一段区间的最大值*最小值. 一个区间左端点在L,右端点在R,那么该区间的长度为(R?L+1). 求长度分别为1-n的区间的最大价值. 保证数据随机 因为保证数据随机,所以我们可以考虑用区间的最大值把这个区间分为两个部分,这样答案的贡献就有两种情况. 1.在同一个区间里 2.跨过最大值,在两个区间里 情况1通过递归就变成了情况2,而情况二我们通过two-points来完成.记录l指针和r指针,因为所求为最大值,所以选取l和r指针较大的内个加入,并每次更新答案

51nod1674:区间的价值2(分治,利用&amp;和|的收敛性)

lyk拥有一个区间. 它规定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积. 例如3个数2,3,6.它们and起来的值为2,or起来的值为7,这个区间对答案的贡献为2*7=14. 现在lyk有一个n个数的序列,它想知道所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果是多少. 例如当这个序列为{3,4,5}时,那么区间1,11,1,1,21,2,1,31,3,2,22,2,2,32,3,3,33,3的贡献分别为9,0,0,16,20,25.