简体   繁体   English

通过连接前 n 个自然数的二进制表示形成的数字的十进制值

[英]decimal value of the number formed by concatenating the binary representations of first n natural numbers

Given a number n , find the decimal value of the number formed by concatenating the binary representations of first n natural numbers.给定一个数字n ,找出通过连接前n 个自然数的二进制表示形成的数字的十进制值。
Print answer modulo 10^9+7.打印答案模 10^9+7。

Also, n can be as big as 10^9 and hence logarithmic time approach is needed.此外, n可以大到 10^9,因此需要对数时间方法。

Eg: n = 4 , Answer = 220例如: n = 4 ,答案 = 220

Explanation : Number formed= 11011100 ( 1=1 , 2=10 , 3=11 , 4=100 ).解释:形成的数字= 11011100 ( 1=1 , 2=10 , 3=11 , 4=100 )。 Decimal value of 11011100 = "220" .十进制值11011100 = "220"

The code I am using below only works for first integers N<=15我在下面使用的代码仅适用于第一个整数N<=15

    String input = "";
    for(int i = 1;i<=n;i++) {
        input += (Integer.toBinaryString(i));
    }
    return Integer.parseInt(input,2);

This solution to this question requires O(N) time.这个问题的解决方案需要O(N)时间。 Luckily this can be solved in O(logN) time.幸运的是,这可以在O(logN)时间内解决。 Also, this is the A047778 sequence:此外,这是A047778序列:

1,6,27,220,1765,14126,113015,1808248,28931977, 462911642,7406586283,118505380540,1896086088653, 30337377418462,485398038695407,15532737238253040, 497047591624097297,15905522931971113522

The sequence follows this recurrence relation:该序列遵循这种递归关系: 在此处输入图像描述 where ⌊.⌋ is floor function其中⌊.⌋是楼层 function

a(n) can also be expressed as sum of multiple arithmetico–geometric series . a(n)也可以表示为多个算术几何级数之和。

If we are interested in a(14) , here's how it can be calculated.如果我们对a(14)感兴趣,下面是它的计算方法。

在此处输入图像描述

Multiplying with powers of two on both sides of the above equations gives equations like the following:在上述等式两边乘以 2 的幂得到如下等式:

在此处输入图像描述

If we add all the above equations, a(14) can be expressed as sum of four arithmetico–geometric series.如果我们将上述所有方程相加, a(14)可以表示为four算术-几何级数之和。 在此处输入图像描述

It's important to note that in all sequences except the first one, the first term of the arithmetic progression is of form重要的是要注意,在除第一个序列之外的所有序列中,等差数列的第一项是形式在此处输入图像描述 and the last term和最后一个学期在此处输入图像描述

The sum of n terms of arithmetico–geometric sequence can be calculated using this formula :可以使用以下公式计算算术几何序列的 n 项之和: 在此处输入图像描述

a(First term of AP), n(Number of terms), d(Common Difference of AP), b(First term of GP), r(Common ratio of GP). 

Since we're interested in a(n) mod 1000000007 and not the actual term a(n) , these modulo arithmetics may come in handy.由于我们感兴趣的是a(n) mod 1000000007而不是实际a(n)项,因此这些模运算可能会派上用场。

在此处输入图像描述

This is a good starting point for implementing division modulo which requires some number theory basics.是实现除法模的一个很好的起点,它需要一些数论基础知识。

Once we figure out the number of sequences required and the five variables a, n, d, b, r for each sequence, a(n) modulo 1000000007 can be calculated in O(logn) time.一旦我们计算出所需的序列数和每个序列的五个变量a, n, d, b, r ,就可以在O(logn)时间内计算出a(n) modulo 1000000007

Here's a working C++ code:这是一个有效的C++代码:

#include <numeric>
#include <iostream>
#define mod long(1e9+7)

long multiply(long a,long b){
    a%= mod;b%= mod;
    return (a*b)%mod;
}

void inverseModulo(long a,long m,long *x,long *y){ //ax congruent to 1 mod m

    if(!a){
        *x=0;
        *y=1;
        return ;
    }
    long x1,y1;
    inverseModulo(m%a,a,&x1,&y1);
    *x=y1-(m/a)*x1;
    *y=x1;
    return;
}

long moduloDivision(long a,long b,long m){  // (a*(returnValue))mod m congruent to b mod m
    //https://www.geeksforgeeks.org/modular-division/ and https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/
    long x,y;
    inverseModulo(b, m, &x, &y);
    x%=m;
    return (x*a)%m;
}

long power(long n,long r){ //calculates (n^r)%mod in logarithmic time
    if(r==0) return 1;
    if(r==1) return n;
    if(r%2){
        auto tmp=power(n, (r-1)/2);
        return multiply(multiply(n,tmp),tmp);
    }
    auto tmp=power(n, r/2);
    return multiply(tmp, tmp);
}
long sumOfAGPSeries(long a,long d,long b,long r,long n){
    if(r==1) return multiply(n, multiply(a, 2)+multiply(n-1, d))/2;
    long left=multiply(multiply(d, r), power(r,n-1)-1);
    left=a+moduloDivision(left,r-1,mod);
    left=multiply(left, b);
    left%=mod;
    long right=multiply(multiply(b, power(r, n)), a+multiply(n-1, d));
    long ans=right-left;
    ans=(ans%mod + mod) % mod;
    return moduloDivision(ans,r-1,mod);

}
signed main(){
    long N=1000;
    long ans = 0;
    long bitCountOfN = log2(N) + 1;
    long nearestPowerOfTwo = pow(2, bitCountOfN - 1);
    long startOfGP = 0;
    while (nearestPowerOfTwo) { // iterating over each arithmetico–geometric sequence
        long a, d, b, r, n;
        a = N;
        d = -1;
        b = power(2, startOfGP);
        r = power(2, bitCountOfN);
        n = N - nearestPowerOfTwo + 1;
        ans += sumOfAGPSeries(a, d, b, r, n);
        ans %= mod;
        startOfGP += n * bitCountOfN;
        N = nearestPowerOfTwo - 1;
        nearestPowerOfTwo >>= 1;
        bitCountOfN--;
    }
    std::cout << ans << std::endl;
    return 0;
}

The validity of the above C++ code can be verified using this trivial python code:可以使用这个简单的python代码来验证上述C++代码的有效性:

def a(n): 
  return int("".join([(bin(i))[2:] for i in range(1, n+1)]), 2)
for n in range(1,100):
  print (a(n)%1000000007)

Note that working with string representation is not necessary (moreover, is not useful after task changing).请注意,不需要使用字符串表示(此外,在任务更改后没有用处)。 Look at approach with bitwise arithmetics (Python, but principle is the same)使用按位算术查看方法(Python,但原理相同)

With new condition concerning modulo 1000000007 we have just add modulo operation to result calculation line at every step, because shift left and or-ing is equivalent to multiplication by power of two and adding, these operations are obeyed to equivalence relations for modulo properties.有了关于模 1000000007 的新条件,我们只需在每一步的结果计算行中添加模运算,因为左移和 or-ing 相当于乘以 2 的幂和加法,这些运算服从模性质的等价关系。 Note that intermediate results don't exceed 1000000007*n , so long type is suitable here for reasonable n values.请注意,中间结果不超过1000000007*n ,因此long类型在这里适用于合理的 n 值。

n = 100  
size = 0   #bit length of addends
result = 0   # long accumulator
for i in range(1, n + 1):    
    if i & (i - 1) == 0:    #for powers of two we increase bit length
        size += 1
    result = ((result << size) | i) % 1000000007   #shift accumulator left and fill low bits with new addend
print(result)

variant without bitwise operations:没有按位运算的变体:

pow2 = 1
nextpow = 2
result = 0   # long accumulator
for i in range(1, n + 1):
    if i == nextpow:    #for powers of two we increase bit length
        pow2 = nextpow
        nextpow = nextpow * 2
    result = (result * pow2  + i) % 1000000007  #shift accumulator left and fill low bits with new addend
    cin>>n;
    ll ans=1;
    ll one=1;
    for(int i=2;i<=n;i++)
    {
        ll digit=log2(i)+1;
        ans=(((ans%N*(one<<digit)%N)%N+i%N)%N);
    }
    cout<<ans<<Ed;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM