ACM/ICPC World Finals 2012 D Fibonacci Words

题目大意

定义斐波那契字符串:

F(n)=01F(i1)+F(i2)(n=0)(n=1)(n2)

*此处的+为字符串加法

求一个01串在

F(n) 中出现的次数

解答

将这个字符串在 F(i) 中出现的次数记为 G(i)
则不难发现: G(i)=G(i1)+G(i2)+F(i1)F(i2)
如果我们把最短的两个比这个01串长的斐波那契字符串记作 a,b
F(i1)F(i2) 交界处无非是 a+bb+a 两种情况而已,因为这两个串不是在 F(i) 的最前面就是在最后面
所以我们只要用KMP找到 a,b,a+b,b+a 中这个串出现的次数,就可以递归求出 G(n) 的结果:

G(n)=0G(n1)+G(n2)+Match(b+a)G(n1)+G(n2)+Match(a+b)(n)(nb)(nb)

参考代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>

using namespace std;

#define LLD long long int

string a, b;
string word;
int len;

LLD serach(string &st, string &word)
{
    int l1 = st.length();
    int l2 = word.length();
    LLD ret = 0;
    bool flag;
    for (int i = 0; i < l1; i++) {
        flag = true;
        for (int j = 0; j < l2; j++)
            if (st[i+j] != word[j]) {
                flag = false;
                break;
            }
        if (flag == true)
            ret++;
    }
    return ret;
}

void makeAns(int n, LLD a, LLD b, LLD da, LLD db)
{
    int times = 0;
    while(times < n) {
        if (times % 2)
            a += b+da;
        else
            b += a+db;
        times++;
    }
    if (times % 2)
        printf("%lld\n", b);
    else
        printf("%lld\n", a);
}

int main()
{
    int n;
    int ca = 1;
    while(scanf("%d", &n) != EOF) {
        printf("Case %d: ", ca++);
        a = "0";
        b = "1";
        cin >> word;
        len = word.length();
        int times = 2;
        if (n == 0) {
            printf("%lld\n", serach(a, word));
            continue;
        }
        if (n == 1) {
            printf("%lld\n", serach(b, word));
            continue;
        }
        while ((a.length() < len || b.length() < len) && times <= n) {
            if (times % 2) {
                b = a+b;
            } else {
                a = b+a;
            }
            times++;
        }
        if (times == n+1) {
            if (times % 2)
                printf("%lld\n", serach(a, word));
            else
                printf("%lld\n", serach(b, word));
            continue;
        }
        times--;
        LLD ser1 = 0, ser2 = 0;
        LLD addser1 = 0, addser2 = 0;
        string tmpstr1, tmpstr2;
        tmpstr1 = a+b;
        tmpstr2 = b+a;
        ser1 = ser2 = addser1 = addser2 = -1;
        ser1 = serach(a, word);
        ser2 = serach(b, word);
        addser1 = serach(tmpstr1, word)-ser1-ser2;
        addser2 = serach(tmpstr2, word)-ser1-ser2;
        if (!(times % 2))
            makeAns(n-times, ser1, ser2, addser2, addser1);
        else
            makeAns(n-times, ser2, ser1, addser1, addser2);
    }
    return 0;
}
点赞