【问题标题】:Count ways to make string with no K consecutive zeroes计算没有 K 个连续零的字符串的方法
【发布时间】:2014-09-21 03:28:51
【问题描述】:

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

现在,问题是我们需要计算填充这些“?”的方法的数量。位置使得没有 K 0 可以放在一起。

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

让 K=3 然后在这里我们可以将“0”放在最多两个位置中的一个位置。所以字符串是:

0100
0010
0110

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

我的方法:

现在我有 O(N,K) 的方法来使用动态编程来解决这个问题,如果我们将 0 放在第 i 个位置,那么我们可以在“?”的下一个连续段中放置 K-1 个零。如果我们放 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";

现在它对于更大的测试用例失败了。但是我在暴力解决方案上运行它并且它不匹配。

测试用例:n=73,k=7 和字符串 s = ???L?R?LLL?L?L?L?LLL???L???RL?????LR?L? LLRL??R???L?RL????RL?R??LL??LLLR?R

答案应该是 877905026。但是代码给出的是 246470268

【问题讨论】:

  • N 和 K 有多大?
  • @PeterdeRivaz 2
  • ?的数量是否有限制
  • @PhamTrung 没有。他们没有这样的限制
  • 好像是项目欧拉问题?

标签: algorithm


【解决方案1】:

提示

您可以使用数组 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;
    }
}

【讨论】:

  • 你能解释一下吗?我认为这个提示并没有完全回答这个问题。但只是其中的一部分
  • 根据您的说法,这是完整的答案吗?我的意思是您在顶部提到了 HINTS。他们的东西还剩下吗?您可以通过将 K=3 和字符串设为 10???0 来解释它吗??跨度>
  • 这个测试用例我认为会解释得更清楚
  • 你如何确保零的数量永远不会达到 K?
  • 因为您最多只能在每个总和中添加 K 个项,并且您只计算以 1 结尾的字符串
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-14
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多