Hdu5921 Binary Indexed Tree

Hdu5921 Binary Indexed Tree

思路

计数问题,题目重点在于二进制下1的次数的统计,很多题解用了数位DP来辅助计算,定义g(i)表示i的二进制中1的个数, $ans = \sum_{i=1}^n \sum_{j=0}^{i-1} g(i,j) = 0.5\sum_{i=0}^n\sum_{j=0}^n[g(i)+g(j)-2g(lcp(i,j))] $

即先计算每个位的贡献,再减去重复的地方。

先计算前者,每个数会出现n+1 次,所以结果乘以n+1 即可,对第i位,统计这一位为1的数,考虑这一位的右边,如果当前数位为1,那么从这一位往后的后缀的数都满足,用r[i-1]表示,即从0~r[i-1]。这一位的左边的前缀的数也都满足,用l[i+1]表示,要乘\(2^i\) 。

同理,计算lcp的计数只需考虑两个数同时满足的情况即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 65;
typedef long long ll;
const ll mod = 1e9+7LL;
int a[N];
ll l[N],r[N],e[N];
ll get(int x){
    ll cnt = 0LL;
    for(int i=0;i<x;i++) cnt += a[i];
    for(int i=x-1;i>=0;i--){
        if(a[i]){
            if(i) cnt += r[i-1];
        }
        {
            cnt += l[i+1]*e[i]%mod;
            cnt %= mod;
        }
    }
    return cnt;
}
ll getlcp(int x){
    ll cnt = 0LL;

    for(int i=x-1;i>=0;i--){
        if(a[i]){
            if(i) (cnt += (r[i-1]+1)*(r[i-1]+1)%mod)%=mod;
            else{
                (cnt += 1LL)%=mod;
            }

            //printf("cnt %lld\n",cnt);
        }
        {

            cnt += l[i+1]*e[i]%mod*e[i]%mod;
            cnt %= mod;
            //printf("cnt %lld\n",cnt);
        }
    }
    //printf("cnt %lld\n",cnt);
    return cnt;
}
int main(){
    int i,T,len,t;
    ll n,m,ans;
    scanf("%d",&t);
    T=0;
    for(int i=0;i<63;i++) e[i]=(1LL<<i)%mod;
    while(t--){
        scanf("%lld",&n);
        m=n;
        len=0;
        for(;m;m>>=1) a[len++]=m%2;
        l[len]=0;
        r[0]=a[0];
        for(i=1;i<len;i++) r[i]=(r[i-1]+a[i]*(1LL<<i)%mod)%mod;
        for(i=len-1;i>=0;i--) l[i] = ((l[i+1]<<1LL) + a[i])%mod;

        ans = ((n+1)%mod*get(len))%mod;
        //printf("%lld\n",ans);
        ans -= getlcp(len);
        ans = (ans%mod+mod)%mod;
        printf("Case #%d: %lld\n",++T,ans);
    }
}

原文地址:https://www.cnblogs.com/wangwangyu/p/9678403.html

时间: 2024-10-08 18:43:31

Hdu5921 Binary Indexed Tree的相关文章

树状数组(Binary Indexed Tree,BIT)

树状数组(Binary Indexed Tree) 前面几篇文章我们分享的都是关于区间求和问题的几种解决方案,同时也介绍了线段树这样的数据结构,我们从中可以体会到合理解决方案带来的便利,对于大部分区间问题,线段树都有其绝对的优势,今天这篇文章,我们就来欣赏由线段树变形的另外一个数据结构--树状数组,树状数组通常也用于解决区间求和.单点更新的问题,而且效率比线段树高一些(树状数组区间求和和单点更新的时间复杂度均为o(log n)),相对而言,线段树的应用范围可能更广泛一些.但不得不承认,树状数组确

SRM 627 D1L2GraphInversionsDFS查找指定长度的所有路径 Binary indexed tree (BIT)

题目:http://community.topcoder.com/stat?c=problem_statement&pm=13275&rd=16008 由于图中边数不多,选择DFS遍历全部路径,计算路径Inversions时使用了一个R[] 数组,能够在O(N)时间内得到路径Inversions,又由于该图所以路径条数为O(N^2),算法复杂度为O(N^3),对于N为1000的限制来说,复杂度较高,但实际測试中,最慢的測试用例费时700多ms,没有超时.若要减小复杂度,须要更高效的算法来计

POJ1990 MooFest 树状数组(Binary Indexed Tree,BIT)

N头牛排成一列,每头牛的听力是Vi,每头牛的位置Pi,任意两头牛i,j相互交流时两头牛都至少需要发出声音的大小为max(Vi,Vj) * |Pi-Pj|,求这N头牛两两交流总共发出的声音大小是多少.N,V,P都是1-20000的范围. 这题首先对Vi从小到大进行排序,排序过后就可以依次计算i,将所有比Vi小的牛到i之间的距离之和乘以Vi得到Ri,然后累加Ri就是最终结果.问题是Ri具体该如何求. 假设听力比Vi小的牛并且位置也比Pi小的牛的个数为Ci,并且这些距离之和为Si,听力比Vi小的所有牛

Binary Indexed Tree (Fenwick Tree)

Binary Indexed Tree 空间复杂度O(N),查询时间复杂度O(lgN). 其中每个元素,存储的是数组中一段(注意起始元素看作1而非0)的和: 假设这个元素下标为i,找到i的最低位1,从最低位1开始的低部表示的是长度,去除最低位1剩下的部分加上1表示的是起始位置,例如: 8二进制表示为100 最低位1也是最高位,从1开始的低部也即100本身,因此长度为8. 去除1以后,剩下为0,加上1以后为1.所以sum[8]表示的是从第1个元素开始的8个元素的和. 又比如11的二进制表示为101

Segment Tree / Binary Indexed Tree

参见 307. Range Sum Query - Mutable Segment Tree Tree Implementation (SegmentTreeNode) https://www.youtube.com/watch?v=rYBtViWXYeI&list=PLLuMmzMTgVK7ug02DDoQsf50OtwVDL1xd&index=1https://leetcode.com/problems/range-sum-query-mutable/discuss/75711/C++

树状树组(Binary Indexed Tree (BIT))的C++部分实现

一.树状数组的用处 树状树组是将一个线性数组保存为“树状”,当修改某点的值.求某个区间的和的时候能够有效的减少时间复杂度.当数组长度为N,实时对数组进行M次修改或求和,最坏的情况下复杂度是O(M*N). 二.树状数组的建立 假设输入数组为 vector<int> nums 将其转化为树状数组的本质在于将数组的原先顺序打乱后,经过特殊的求和方法,组合成新的数组,代码如下.关键点在于k+=k&-k,这是一个利用二进制码的特点完成树状数组下标的选取. 1 size = nums.size()

Binary Indexed Tree (树状数组)

树状数组是能够完成下述操作的数据结构 给一个初始值全为0的数列a1,a2,-an. *给定i,计算a1+a2+-+ai *给定i和x,执行ai += x 1.基于线段树的实现 如果使用线段树,只需要对RMQ的样例做少许修改就可以实现这两个功能.线段树的每个节点上维护的是对应的区间的和. 接下来,我们来看如何计算从s到t的和.在基于线段树的实现中,这个和是可以直接求得的. 但是如果我们能够计算(从1到t的和)-(从1到s-1的和),同样可以得到s到t的和.也就是说,只要对于任意i,我们都能计算出1

树状数组(Binary Indexed Tree)

对于学习的线段树方面的,发现很多问题可以用它来求解,但是做题的时候发现,用线段树太容易tle也,很多次也是卡时间过的,然后就发现了树状数组. 首先我们搞明白树状数组是用来干嘛的,树状数组是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值,经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询). 所以说,树状数组的求解和线段树的求解有些重合,但是功

[LeetCode] Find Mode in Binary Search Tree 找二分搜索数的众数

Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST. Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than or equal to the nod