第n个具有两个设置位的数字n,范围从1到10 ^ 14

时间:2018-10-07 15:30:41

标签: java

请看以下顺序:3、5、6、9、10、12、17、18、20 ...

该系列中的所有数字在其二进制表示形式中均已精确设置了2位。您的任务很简单,您必须找到此序列的第N个数字。 对于每个测试用例,打印序列的第N个数字,并用换行符分隔。由于数量可能非常大,请打印number % 1000000007

我无法弄清楚为什么某些测试用例失败,并且我的代码将在指定范围内工作。

这是我的代码段:

public class Solution {
    public static void main(String[] args) {
        /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
        Scanner scan=new Scanner(System.in);
        int t = scan.nextInt();
        for(int j=0 ; j<t ; j++){
            long n=scan.nextInt();
            long r = 0;
            long i = 1;
            while((r = i*(i+1)/2) < n)
            {
                i++;
            }
            long res = (1<<i) + (1 << (i-(r-n)-1));
            System.out.println(res);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

这是一个序列,因此您可以查看正确的百科全书OEIS - Sum of two distinct powers of 2,以查找所需的每条信息。
您还将找到算法。这是其中之一的Java翻译。

for (int j = 0; j < t; j++) {
    long n = scan.nextInt();
    if (n < 1954) {
        nthLongTwoBitSets(n);
    } else {
        nthBigIntegerTwoBitSets(n);
    }
}

ri是两个设置位的索引。
如果必须乘或除以2的幂,则可以使用位移运算符来加快运算速度。
一旦long的数量变大,就必须使用BigInteger

编辑:由于“打印数量%1000000007”,因此您必须在类中声明以下变量
private static final BigInteger MOD = new BigInteger("1000000007");
然后,我们将使用模块运算符。

public static void nthLongTwoBitSets(long n) {
    long r = ((long) Math.sqrt((n << 3) - 1) + 1) >>> 1;
    long i = n - ((r * (r - 1)) >>> 1) - 1;
    long result = (1L << r) | (1L << i);
    result %= 1000000007;
    System.out.println(result);
}

public static void nthBigIntegerTwoBitSets(long n) {
    int r = ((int) Math.sqrt((n << 3) - 1) + 1) >>> 1;
    int i = (int) n - ((r * (r - 1)) >>> 1) - 1;
    BigInteger result = BigInteger.ZERO.setBit(r).setBit(i).mod(MOD);
    System.out.println(result.toString());
}

Edit2 :我无法访问该链接,但是如果运行时错误是由于超时导致的,我们就必须进行一些微优化(在几乎每种情况下都是不正确的做法),因此1)不再使用BigInteger,而2)仅使用一个System.out.println,因为它非常昂贵。我们将字符串存储在StringBuilder

public class Solution {

    private final static long MOD = 1000000007L;
    private final static long FIXED = 46480318; // (1L << 42) % mod;

    public static void main(String[] args) {

        String sep = "\n";
        StringBuilder sb = new StringBuilder(90000);
        Scanner scan = new Scanner(System.in);
        int t = scan.nextInt();
        for(int j=0 ; j<t ; j++){
            long n = scan.nextInt();
            sb.append(nthLongTwoBitSets(n));
            sb.append(sep);
        }
        sb.deleteCharAt(sb.length() - 1);
        System.out.println(sb.toString());
    }

    public static long nthLongTwoBitSets2(final long n) {
        long r = ((long) Math.sqrt((n << 3) - 1) + 1) >>> 1;
        long i = n - ((r * (r - 1)) >>> 1) - 1;
        long rMod = 1;
        while (r > 62) {
            r -= 42;
            rMod *= FIXED;
            rMod %= MOD;
        }
        rMod *= (1L << r);
        rMod %= MOD;
        long iMod = 1;
        while (i > 62) {
            i -= 42;
            iMod *= FIXED;
            iMod %= MOD;
        }
        iMod *= (1L << i);
        iMod %= MOD;
        final long result = (rMod + iMod) % MOD;

        return result;
    }
}