计算制作没有K连续零的字符串的方法

时间:2014-09-19 10:11:06

标签: algorithm

给定一个长度为N且仅由0和1组成的字符串。但是字符串的某些位置是'?'。这意味着它们可以放0或1。

现在,问题是我们需要计算填充这些内容的方法数量?'可以将No K 0组合在一起的位置。

比如说我们有长度为N = 4且字符串为0 ?? 0的字符串

然后让K = 3然后在这里我们可以把' 0'仅在两个最大的一个位置。所以字符串是:

0100
0010
0110

所以这里的回答是3.现在给定长度为N和K的字符串,我们需要计算制作这个字符串的方法的数量。

我的方法:

现在我正在采用O(N,K)方法来解决这个问题,使用动态编程,如果我们将0放在第i位置,那么我们可以将K-1零放在'?&#39的下一个连续段中;如果我们放1,那么我们可以再次使用K零。

但N和K可能非常大。那么它们是一些更好,更有效的算法吗?

其中一个答案中提到的代码:

int n,k;
cin>>n>>k;
string s;
cin>>s;
s="#"+s;
int size=s.length();

vector<long long int>F(size+1);
F[0]=1;
for(int i=1;i<=size;i++){
    if(s[i]=='R')
    {
        F[i]=0;
    }       
    else if(s[i]=='L'){
        F[i]=1;
    }
    else{
        for(int j=i-1;j>=i-k;j--){
            if(j<0)
            break;
            F[i]=(F[i]+F[j])%MOD;
        }
    }
}
cout<<F[size]<<"\n";

现在它的测试用例没那么大了。但是我在abrute force解决方案上运行它并没有匹配。

测试案例:n = 73,k = 7,字符串s = L?R?LLL?L?L?L?LLL L ??? RL?LR?L? LLRL ?? R 111 L&RL ???? RL?R 10 LL ?? LLLR·R

答案应该是877905026.但是代码是246470268

1 个答案:

答案 0 :(得分:1)

HINTS

您可以使用数组F [n]来计算填充位置[0,n]的方式的数量,使得没有K连续的0并且在位置n-1处存在1。

然后根据先前的结果计算F [n + 1],我们知道在位置n处有1,在0和K-1之前存在零。设零的数量为k。

F[0] = 1
F[n] = sum F[n-1-k] for k in 0,1,..,K-1 
   (only including values for k up to where the string at n-1-k is forced to be 1)

这应该给出正确答案,但需要时间O(NK)。

但是,我们可以通过维持F [n]的值的前缀和来加速和的计算。换句话说,如果我们存储一个数组S [n] = F [0] + F [1] + F [2] + .. + F [n],我们可以通过减去快速计算F的特定指数的总和两个S [n]值。

因此,通过跟踪强制1的最后位置,您可以计算O(N)中的重现。

最终答案将由F [N + 1]给出。

示例1

对于K = 3的示例和0 ?? 0的字符串:

F[0] = 1  (Just the empty string)
F[1] = 0 : position n-1=0 is forced to be 0 so no solutions are possible
F[2] = F[1]+F[0] = 1  (Just the string 01)
F[3] = F[2]+F[1]+F[0] = 2 (The strings 001 and 011)
F[4] = 0 : position n-1=3 is forced to be 0 so no solutions possible
F[5] = F[4]+F[3]+F[2] = 3  (the strings 0010 and 0110 and 0000)

所以最后的答案是3

示例2

对于你的第二个例子10 ??? 0 ??

F[0] = 1 (empty string)
F[1] = 1 (The string 1)
F[2] = 0
F[3] = F[2]+F[1] = 1 (The string 101)
F[4] = F[3]+F[2]+F[1] = 2 (The strings 1011 and 1001)
F[5] = F[4]+F[3]+F[2] = 3 (10011 and 10111 and 10001)
F[6] = 0
F[7] = F[6]+F[5]+F[4] = 5 (1011001, 1001001, 1001101, 1011101, 1000101)
F[8] = F[7]+F[6]+F[5] = 8 (10110011, 10010011, 10011011, 10111011, 10001011, 10011001, 10111001, and 10001001)
F[9] = F[8]+F[7]+F[6] = 13
           10110011, 10010011, 10011011, 10111011, 10001011, 10011001, 10111001, 10001001
           10110010, 10010010, 10011010, 10111010, 10001010

修复代码

你的代码几乎是正确的:内部循环改变如下,它给你想要的答案:

if(s[i]=='R')
{
    F[i]=0;
} else{
    for(int j=i-1;j>=i-k;j--){
        if(j<0)
            break;
        F[i]=(F[i]+F[j])%MOD;
        if (s[j]=='L')
            break;
    }
}