找到n位数的子序列数,可以被8整除

时间:2017-01-11 17:26:56

标签: string algorithm time-complexity dynamic-programming combinatorics

给定n = 1到10 ^ 5,以十进制格式存储为字符串。

示例:如果n = 968,则在所有子序列中,即9,6,8,96,68,98,968中,有3个子序列,即968,96和8,可被8整除所以答案是3。

由于答案可能非常大,请打印答案模(10 ^ 9 + 7)。

4 个答案:

答案 0 :(得分:2)

您可以使用动态编程。设f(len, sum)为长度为len的前缀的子序列数,使其总和为sum模8(sum的范围为0到7)。

f len = 1的值很明显。过渡如下:

  1. 我们可以在新位置开始一个新的子序列:f(len, a[i] % 8) += 1

  2. 我们可以从较短的前缀继续任何子序列:

    for old_sum = 0..7
         f(len, (old_sum * 10 + a[i]) % 8) += f(len - 1, old_sum) // take the new element
         f(len, old_sum) += f(len - 1, old_sum) // ignore the new element
    
  3. 当然,您可以执行所有计算模块10 ^ 9 + 7并使用标准整数类型。

    1. 答案是f(n, 0)(所有元素都被考虑在内,模8的总和为0)。
    2. 此解决方案的时间复杂度为O(n)(因为有O(n)个状态,每个状态有两个转换。)

      注意:如果数字不能有前导零,那么你可以再添加一个参数:一个标志,指示子序列的第一个元素是否为零(这个序列永远不应该被扩展)。其余解决方案保持不变。

答案 1 :(得分:2)

注意:此答案假定您的意思是连续的子序列。

可以被8整除的数字的可分性规则是该数字的最后三位数是否可被8整除。使用此算法,可以获得{{1}的简单O(n)算法}是数字中的位数。

  1. nN=a_0a_1...a_(n-1)的十进制代表,数字为N
  2. 让目前为止的序列数为n
  3. 对于每组三位数s = 0,检查该数字是否可被a_i a_(i+1) a_(i+2)整除。如果是,请将8添加到序列数中,即i + 1。这是因为s = s + i的所有字符串a_k..a_(i+2)都可以被8整除,范围为k
  4. 0..ii循环0并继续。
  5. 因此,如果您有n-2-1,则可分割的子序列位于:

    1. 1424968i=1产生424个数字:i+1 = 2424
    2. 1424i=3产生496个数字:i+1 = 4496249642496
    3. 142496i=4产生968个数字:i+1 = 5968496824968,{{1} })
    4. 请注意,需要进行一些小的修改,以考虑长度小于三位的数字。

      因此序列总数= 424968。总复杂度= 1424968,其中2 + 4 + 5 = 11是位数。

答案 2 :(得分:0)

这不是代码编写服务,所以我会给你足够的信息。

子序列可以有10种可能的状态。第一种是空的。第二个是有一个领先的0.而另外8个是一个正在进行的数字,它是0-7 mod 8.你从字符串的开头开始,有1种方式是空的,没有办法成为别的东西。在字符串的末尾,您的答案是前导0加上正在进行的数字为0 mod 8的方式的数量。

过渡表应该是显而易见的。其余的只是正常的动态编程。

答案 3 :(得分:0)

可以使用以下事实:对于任何三位数abc,以下内容为:

abc % 8 = ((ab % 8) * 10 + c) % 8

或换句话说:具有固定起始索引的数字的测试可以级联:

int div8(String s){
    int total = 0, mod = 0;

    for(int i = 0; i < s.length(); i++)
    {
        mod = (mod * 10 + s.charAt(i) - '0') % 8

        if(mod == 0)
            total++;
    }

    return total;
}

但是我们没有固定的开始指数! 嗯,这很容易解决:

假设有两个序列abint(a) % 8 = int(b) % 8b的后缀是a。无论序列如何继续,ab的模数将始终保持相等。因此,足以跟踪共享具有等值8的属性的序列的数量。

final int RESULTMOD = 1000000000 + 7;

int div8(String s){
    int total = 0;
    //modtable[i] is the number of subsequences with int(sequence) % 8 = i
    int[] modTable = new int[8];

    for(int i = 0; i < s.length(); i++){
        int[] nextTable = new int[8];

        //transform table from last loop-run (shared modulo)
        for(int j = 0; j < 8; j++){
            nextTable[(j * 10 + s.charAt(i) - '0') % 8] = modTable[j] % RESULTMOD;
        }

        //add the sequence that starts at this index to the appropriate bucket
        nextTable[(s.charAt(i) - '0') % 8]++;

        //add the count of all sequences with int(sequence) % 8 = 0 to the result
        total += nextTable[0];
        total %= RESULTMOD;

        //table for next run
        modTable = nextTable;
    }

    return total;
}

运行时为O(n)