SRM541 Div1 Medium(550) AkariDaisukiDiv1

AkariDaisukiDiv1

3通りの場合に分けて考える。fk(S)が短い間は、そのまま計算すれば良い。fk(S)が長くなったら、文字列の連結によってfk(S)の中央に新たにFが現われることは無くなるので、接頭辞と接尾辞のみを覚えておいて計算する。kが大きくなると、C(k)をfk(S)が含むFの個数として、C(i)-2*C(i-1)が一定となるので、数字の計算だけで答えが求められる。

#include <string>
#include <vector>
using namespace std;

string f( string Waai, string Akari, string Daisuki, string X )
{
    return Waai + X + Akari + X + Daisuki;
}

int count( string S, string F )
{
    int c = 0;
    for ( int i=0; i<(int)S.size()-(int)F.size()+1; i++ )
        if ( S.substr(i,F.size())==F )
            c++;
    return c;
}

class AkariDaisukiDiv1{public:
int countF( string Waai, string Akari, string Daisuki, string S, string F, int k )
{
    long long M = 1000000007;

    //  C[i]: f^i(S)が含むFの個数
    vector<int> C(1,count(S,F));

    //  ナイーブに計算
    int i=1;
    for ( ; (int)S.length()<1000; i++ )
    {
        S = f(Waai,Akari,Daisuki,S);
        C.push_back(count(S,F));
    }

    //  接頭辞と接尾辞のみを保持して計算
    string pref = S.substr(0,100);
    string suff = S.substr(S.length()-100);

    int d = 0;      //  Fの出現回数の増分

    for ( ; i<1000; i++ )
    {
        d = 0;
        
        //  Waai X が含みXが含まない、Fの個数
        string t = Waai+pref;
        for ( int j=0; j<(int)Waai.length(); j++ )
            if ( t.substr(j,F.length())==F )
                d++;
        //  X Akari X が含みXが含まない、Fの個数
        t = suff + Akari + pref;
        for ( int j=(int)(suff.length()-F.length()+1);
              j<(int)(suff.length()+Akari.length()); j++ )
            if ( t.substr(j,F.length())==F )
                d++;

        //  X Daisuki が含みXが含まない、Fの個数
        t = suff + Daisuki;
        for ( int j=(int)(suff.length()-F.length()+1);
              j<(int)(suff.length()+Daisuki.length()-F.length()+1); j++ )
            if ( t.substr(j,F.length())==F )
                d++;

        C.push_back((C[i-1]*2+d)%M);

        pref = (Waai+pref).substr(0,100);
        suff = (suff+Daisuki).substr(suff.length()+Daisuki.length()-100);
    }
    
    if ( (int)C.size()>=k+1 )
    {
        return C[k];
    }
    else
    {
        long long c = C[i-1];
        for ( ; i<=k; i++ )
            c = (c*2+d)%M;
        return (int)c;
    }

}};