Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 求一个n位数的子序列的个数,这些子序列可以被8整除_String_Algorithm_Time Complexity_Dynamic Programming_Combinatorics - Fatal编程技术网

String 求一个n位数的子序列的个数,这些子序列可以被8整除

String 求一个n位数的子序列的个数,这些子序列可以被8整除,string,algorithm,time-complexity,dynamic-programming,combinatorics,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)。这不是一项代码编写服务,因此我将为您提供足够的答案 子序列可以处于10种可能的状态。第一个是空的。第二个是有一个领先的0。另外8是一个持续的数字,是0-7 mod 8。从字符串的开头开始,有一种方式是空的,没有其他方式。在字符串的末尾,您的答案是前导0加上

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

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


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

这不是一项代码编写服务,因此我将为您提供足够的答案

子序列可以处于10种可能的状态。第一个是空的。第二个是有一个领先的0。另外8是一个持续的数字,是0-7 mod 8。从字符串的开头开始,有一种方式是空的,没有其他方式。在字符串的末尾,您的答案是前导0加上当前数字0 mod 8的方法数


过渡表应该是显而易见的。剩下的就是普通的动态规划。

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

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

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

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

    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
    
  • 当然,您可以执行模块10^9+7中的所有计算,并使用标准整数类型

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


    注意:如果数字不能有前导零,则可以只向状态添加一个参数:一个指示子序列的第一个元素是否为零的标志(此序列不应扩展)。解决方案的其余部分保持不变。

    注意:此答案假设您指的是连续的子序列

    可被
    8
    整除的数字的可整除性规则是如果该数字的最后三位数字可被8整除。使用此方法,可以获得一个简单的
    O(n)
    算法,其中
    n
    是数字中的位数

  • N=a\u 0a\u 1…a\u(N-1)
    N
    的十进制表示形式,用
    N
    数字表示
  • 让到目前为止的序列数为
    s=0
  • 对于每组三位数字,
    a_i a_(i+1)a_(i+2)
    ,检查数字是否可被
    8
    整除。如果是这样,则将
    i+1
    添加到序列数中,即
    s=s+i
    。这是因为
    a_k..a_(i+2)
    k
    范围为
    0..i
    的所有字符串都可以被
    8
    整除
  • i
    0
    循环到
    n-2-1
    并继续
  • 因此,如果您有
    1424968
    ,则可分割的子序列位于:

  • i=1
    424
    产生
    i+1=2
    数字:
    424
    1424
  • i=3
    496
    产生
    i+1=4
    数字:
    496
    2496
    42496
    142496
  • i=4
    968
    产生
    i+1=5
    数字:
    968
    4968
    24968
    424968
    1424968
  • <>请注意,在长度小于三个数字的情况下,需要进行一些小的修改。


    因此,序列的总数=
    2+4+5=11
    。总复杂度=
    O(n)
    其中
    n
    是位数。

    可以使用以下事实,即对于任何三位数
    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;
    }
    

    运行时是
    O(n)

    到目前为止您尝试了什么?它有一个动态编程标签。你对状态和转换有什么想法吗?如果字符串是
    88
    ,答案是什么?它是3(8,8和88)还是2(只计算8一次)?它们是真的,还是子字符串?可以有
    2^(10^5)
    子序列,这相当多…@VincentvanderWeele你从哪里得到的?10^5以下的大多数数字都是4位数,因此只有2^4个子序列。这并不多。@b标题上说这是一个n位数,其中n最多可以达到100000,对吗?是的,利用整除性规则比任何检查单个子序列的“幼稚”方法都要容易得多。这将是子序列的正确解决方案,而不是子串+1
    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;
    }