首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

分享近来看到的一个不错的题目

2012-10-17 
分享最近看到的一个不错的题目斐波那契字符串的定义如下:f1 af2 bfn fn-1 fn-2, n2所以前6个斐波那

分享最近看到的一个不错的题目


斐波那契字符串的定义如下:

f1 = a
f2 = b
fn = fn-1 fn-2, n>2

所以前6个斐波那契字符串是:"a", "b", "ba", "bab", "babba", "babbabab"

1 对应 a
2 对应 b
3 对应 ba

现在给出1个编号m,对应一个字符串fm。再给出一些字符串,s0,s1...si,求fm中,s0,s1...si各出现了多少次。

例如:m = 6,fm = babbabab
给出的字符串为:a,b,ab,aba,其中a出现了3次,b出现了5次,ab出现了3次,aba出现了1次。

[解决办法]
写了一个求fm的程序,由打印结果,可以知道a,ba,aba等 之间的关系,
但是我还没发现规律,在这儿先UP一下.

C/C++ code
#include <conio.h>#include <string>#include <iostream>using namespace std;string fn(string& strFn1,string& strFn2){    return strFn1.append(strFn2);}string fm(int m){    if (m==1)    {        return "a";    }    if (m==2)    {        return "b";    }    if(m>2)    {        return fn(fm(m-1),fm(m-2));    }}int main(int argc,char* argv[]){    for (int i = 2;i<10;i++)    {        cout<<i<<" "<<fm(i)<<endl;    }        getch();    return 0;}
[解决办法]
2 b
3 ba
4 bab
5 babba
6 babbabab
7 babbababbabba
8 babbababbabbababbabab
9 babbababbabbababbababbabbababbabba

求a,b,ab,aba出现了几次,是否可以转化成 对数值的计算?
a=1;
b=2;
aba=??
babbabab:a=3
babbabab:b=5
babbabab:ba=3
babbabab:aba=1

1 a 1
11 b 2 
121 ba 3
1331 bab 4
14641 babba 5
15101051 babbabab 6


之间有什么关系?
[解决办法]
这要靠斐波那契树的性质吧。
1. 首先si里出现连续2个a或者连续3个b=>无解。|s|=1特解做掉。于是下面假设|s|=k>1
2. 然后枚举s的分割,s=uv,|u|,|v|>0,并计算出最小的x,y使得u是fx的后缀,v是fy的前缀。这里y好算,x会复杂一点,但是O(x)时间里应该是能算出x的,而x<=|u|,y<=|v|,所以可以在O(k)算出x,y。
3. 然后就是枚举n,计算fn是否以f[n-1]以u结尾,f[n-2]以v开头的形式包含s。如果是的话,最终答案+F[m-n+1]。这一步可以直接通过观看斐波那契树的形状,以及刚才的x,y来确定,而不用生成fn。如果没错的话对于一个确定的n可以O(1)确定是否有这种包含。
4. 当n和uv枚举完的时候答案应该就是了,复杂度O(k*k*m)=O(m*k^2)。

其中第2步我信心不足。你们来验证一下。
[解决办法]
复杂度来看我的approach还是比较接近的。第2步估计很难有啥优化余地,第3步可能可以把所有的n一起算掉,然后用矩阵乘法做答案相加,做个看上去O(k^2*log(m))的东西。不过好多细节都还待填
[解决办法]
C/C++ code
int getminsuffix(const char* str, int len){    int cur = str[len-1] == 'a' ? 1 : 2;    if(len == 1)        return cur;    if(len >= 2 && cur == 1)        if(str[len-1] == str[len-2])            return -1; //ends with "bb"        else            cur = 3; //ends with "ba"    char* buf = new char[len*2];    buf[0] = 'b';    buf[1] = 'a';    buf[2] = 'b';    int a = cur==3 ? 2 : 1, b = 1;    int result = -1;    const char* p = str+len-(cur==3?2:1/*F[cur]*/)-1;    while(p >= str)    {        for(int i=0;i<a;i++)            buf[a+b+i] = buf[i];        for(int i=a+b-1;i>=0 && p>=str;i--,p--)            if(*p != buf[i])                goto error;        b += a;        a += b;        for(int i=0;i<b;i++)            buf[a+i] = buf[i];        cur += 2;    }    result = cur;error:    delete[] buf;    return result;}int getminprefix(const char* str, int len){    if(str[0] == 'a')        return len==1 ? 1 : -1;    if(len == 1) return 2;    if(len == 2) return str[1]=='a' ? 3 : -1;    int a = 1, b = 1, cur = 3;    while(a+b < len)    {        for(int i=0;i<a && a+b+i<len;i++)            if(str[i] != str[a+b+i])                return -1;        int temp = a+b;        b = a;        a = temp;        cur++;    }    return cur;}int solve(int m, const string& s){    int result = 0;    int F[30] = {0,1};    for(int i=2;i<30;i++)        F[i] = F[i-1] + F[i-2];    int k = s.length();    if(k == 1)    {        if(m == 1 && s[0] == 'a') return 1;        return s[0] == 'b' ? F[m-1] : F[m-2];    }    //assume no consecutive 2 'a's and 3 'b's for now    for(int i=1;i<k;i++)    {        int x = getminsuffix(s.c_str(), i);        int y = getminprefix(s.c_str()+i, k-i);        if(x < 0 || y < 0) continue;        if(y == 1)        {            //only f[3] will be a possible case here            result += x==2 ? F[m-2] : 0;            continue;        }        //naive sum below        /*for(int j=max(x+1,y+2);j<=m;j++)            if((j-x)%2 != 0)                result += F[m-j+1];*/        //optimized sum        int from = max(x+1, y+2);        if((from-x)%2 == 0) from++;        int to = m;        if((from+to)%2 != 0) to--;        from = m-from+1;        to = m-to+1;        //result is F[to]+F[to+2]+...+F[from]        if(to <= from)            result += F[from+1] - F[to-1];    }    return result;} 


[解决办法]
我想到个优化。

2. 然后枚举s的分割,s=uv,|u|,|v|>0,并计算出最小的x,y使得u是fx的后缀,v是fy的前缀。这里y好算,x会复杂一点,但是O(x)时间里应该是能算出x的,而x<=|u|,y<=|v|,所以可以在O(k)算出x,y。

这一步应该可以通过递推,在线性时间里做出所有的x,y。这个可以线性的话那整个复杂度就直接把L^2*logm变成L*logm了。如果线性能出的话,加大数据量然后只求是否是子串,或者求答案mod n,这题就很硬了。
[解决办法]
其实,L=10^4,sum L=10^5的话估计人家想要的就是L*log(m)的算法了。那也就是说刚才那个优化是可行的。等我有心情了把代码写一下
[解决办法]
这样应该对吧

C/C++ code
string fun(int m,int t[]){    t[m]++;    if(m==0)    {        return "a";    }    if(m==1)        return "b";    return fun(m-1,t)+fun(m-2,t);}int main(){    string data="babbabab",s0="a",s1="b",s2="ba";    int m=6;    int* t=new int[m];    for(int j=0;j<m;j++)        t[j]=0;    fun(m-1,t);    for(int i=0;i<m;i++)    {        cout<<t[i]<<endl;    }    return 0;} 

热点排行