【发布时间】:2021-02-25 16:45:25
【问题描述】:
问题陈述:位串的斐波那契字序列定义为:
F(0) = 0, F(1) = 1
F(n - 1) + F(n - 2) 如果 n ≥ 2
例如:F(2) = F(1) + F(0) = 10,F(3) = F(2) + F(1) = 101,等等。
给定一个位模式 p 和一个数字 n,p 在 F(n) 中出现的频率是多少?
输入:
每个测试用例的第一行包含整数 n (0 ≤ n ≤ 100)。第二行包含位
模式 p。模式 p 是非空的,长度最多为 100 000 个字符。
输出:
对于每个测试用例,显示其用例编号,后跟位模式 p 的出现次数
F(n)。事件可能重叠。出现次数将少于 2^63。
样本输入:
6
10
样本输出:
案例1:5
根据我在互联网上找到的提示,我实现了一个分而治之的算法来解决这个问题:我们可以认为从 F(n-1) 到 F(n) 的过程为字符串替换规则:每个 '1' 变成 '10' 而 '0' 变成 '1'。这是我的代码:
#include <string>
#include <iostream>
using namespace std;
#define LL long long int
LL count = 0;
string F[40];
void find(LL n, char ch1,char ch2 ){//Find occurences of eiher "11" / "01" / "10" in F[n]
LL n1 = F[n].length();
for (int i = 0;i+1 <n1;++i){
if (F[n].at(i)==ch1&&F[n].at(i+1)==ch2) ++ count;
}
}
void find(char ch, LL n){
LL n1 = F[n].length();
for (int i = 0;i<n1;++i){
if (F[n].at(i)==ch) ++count;
}
}
void solve(string p, LL n){//Recursion
// cout << p << endl;
LL n1 = p.length();
if (n<=1&&n1>=2) return;//return if string pattern p's size is larger than F(n)
//When p's size is reduced to 2 or 1, it's small enough now that we can search for p directly in F(n)
if (n1<=2){
if (n1 == 2){
if (p=="00") return;//Return since there can't be two subsequent '0' in F(n) for any n
else find(n,p.at(0),p.at(1));
return;
}
if (n1 == 1){
if (p=="1") find('1',n);
else find('0',n);
return;
}
}
string p1, p2;//if the last character in p is 1, we can replace it with either '1' or '0'
//p1 stores the substring ending in '1' and p2 stores the substring ending in '0'
for (LL i = 0;i<n1;++i){//We replace every "10" with 1, "1" with 0.
if (p[i]=='1'){
if (p[i+1]=='0'&&(i+1)!= n1){
if (p[i+2]=='0'&&(i+2)!= n1) return;//Return if there are two subsequent '0'
p1.append("1");//Replace "10" with "1"
++i;
}
else {
p1.append("0");//Replace "1" with "0"
}
}
else {
if (p[i+1]=='0'&&(i+1)!= n1){//Return if there are two subsequent '0'
return;
}
p1.append("1");
}
}
solve(p1,n-1);
if (p[n1-1]=='1'){
p2 = p1;
p2.back() = '1';
solve(p2,n-1);
}
}
main(){
F[0] = "0";F[1] = "1";
for (int i = 2;i<38;++i){
F[i].append(F[i-1]);
F[i].append(F[i-2]);
}//precalculate F(0) to F(37)
LL t = 0;//NumofTestcases
int n; string p;
while (cin >> n >> p) {
count = 0;
solve(p,n);
cout << "Case " << ++t << ": " << count << endl;
}
}
上述程序运行良好,但只有少量输入。当我将上述程序提交给 codeforces 时,我得到了一个错误的答案,因为尽管我缩短了模式字符串 p 并将 n 减少到 n',但 F[n'] 的大小仍然非常大(n'>=50)。我如何修改我的代码以使其在这种情况下工作,或者是否有另一种方法(例如动态编程?)。非常感谢您的任何建议。
-
有关该问题的更多详细信息可以在这里找到:https://codeforces.com/group/Ir5CI6f3FD/contest/273369/problem/B
【问题讨论】:
标签: recursion dynamic-programming fibonacci divide-and-conquer