可被n整除的给定数组的子序列数

时间:2015-06-27 09:03:20

标签: algorithm

我有一系列数字说1,2,4,0我必须找到可被6整除的序列号。

所以我们将有0,12,24,120,240,这意味着答案将是5,

问题在于我设计了一种算法,该算法需要O(2^n)时间复杂度,因此基本上它会遍历所有可能的天真。

是否有某种方法可以降低复杂性。

Edit1:允许多个数字副本。例如输入可以是1,2,1,4,3 Edit2:数字应按顺序排列,如上例42 420等不允许

代码:此代码无法考虑120

`#include <stdio.h>
 #include<string.h>
 #define m 1000000007
 int main(void) {
 int t;
 scanf("%d",&t);
 while(t--)
 {
    char arr[100000];
    int r=0,count=0,i,j,k;
    scanf("%s",&arr);
    int a[100000];
    for(i=0;i<strlen(arr);i++)
    {
        a[i]=arr[i]-'0';
    }
    for(i=0;i<strlen(arr);i++)
    {
        for(j=i;j<strlen(arr);j++)
        {
            if(a[i]==0)
            {
                count++;
                goto label;
            }
            r=a[i]%6;
            for(k=j+1;k<strlen(arr);k++)
            {
                r=(r*10 + a[k])%6;
                if(r==0)
                count++;
            }
        }
        label:;
        r=0;
    }
    printf("%d\n",count);
 }
 return 0;
}

1 个答案:

答案 0 :(得分:6)

您可以使用动态编程。

像往常一样,当我们决定使用动态编程解决问题时,我们首先将一些输入值转换为参数,然后添加一些其他参数。

参数的明显候选者是序列的长度。 我们的序列为a[1]a[2]...a[N]。 因此,我们搜索f(n)(从n0的{​​{1}})值Na[1]的子序列数,a[2]...,当作为数字读取时,可被a[n]整除。 当我们知道D=6时,计算f(n)看起来并不明显,所以我们深入研究细节。

仔细看看,我们现在面临的问题是,在数字末尾添加一个数字可以将f(n-1)整除的数字变为不能被D整除的数字,反之亦然。 尽管如此,当我们在数字的末尾添加一个数字时,我们确切地知道余数是如何变化的。

如果我们有一个序列Dp[1]p[2]...并且知道p[k],那么数字r模数的其余部分p[1] p[2] ... p[k],然后将D添加到序列中,新号码p[k+1]s的余数p[1] p[2] ... p[k] p[k+1]很容易计算:D

考虑到这一点,我们可以将余数模数为s = (r * 10 + p[k+1]) mod D我们的新参数。 因此,我们现在搜索Df(n,r)n0Nr0)是D-1a[1]a[2]...的子序列数,当读作数字时,余数为a[n]r

现在,知道Df(n,0)f(n,1)...,我们想要计算f(n,D-1)f(n+1,0),{{1} },f(n+1,1)。 对于...f(n+1,D-1)a[1]a[2]的每个可能子序列,当我们考虑元素编号...时,我们要么为其添加a[n] ,或省略n+1并保持子序列不变。 这通过前向动态编程而不是公式更容易表达:

a[n+1]

结果a[n+1](取决于let f (n + 1, *) = 0 for r = 0, 1, ..., D - 1: add f (n, r) to f (n + 1, r * 10 + a[n + 1]) // add a[n + 1] add f (n, r) to f (n + 1, r) // omit a[n + 1] ,是一个或多个术语的总和)是f (n + 1, s)s,{{的子序列数1}},a[1]a[2]产生余数... modulo a[n]

整个解决方案如下:

a[n+1]

我们从答案中减去一个,因为空子序列不被视为数字。

时间和内存要求为s。 当我们注意到,在每个给定时刻,我们只需要存储Dlet f (0, *) = 0 let f (0, 0) = 1 // there is one empty sequence, and its remainder is 0 for n = 0, 1, ..., N - 1: let f (n + 1, *) = 0 for r = 0, 1, ..., D - 1: add f (n, r) to f (n + 1, r * 10 + a[n + 1]) // add a[n + 1] add f (n, r) to f (n + 1, r) // omit a[n + 1] answer = f (N, 0) - 1 ,我们可以将内存降低到O (N * D),因此O (D)的存储空间可以是{ {1}}代替f (n, *)

您的示例序列的插图:

f (n + 1, *)

练习:如何使用此解决方案摆脱前导零的数字? 我们还需要另一个参数吗?