String 求一个n位数的子序列的个数,这些子序列可以被8整除
给定n=1到10^5,以十进制格式存储为字符串 示例:如果n=968,则在所有子序列(即9、6、8、96、68、98、968)中,有3个子序列(即968、96和8)可被8整除。因此,答案是3String 求一个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加上
由于答案可能非常大,请打印答案的模(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
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;
}