Censored!

Censored!

其实这题的思路也大同小异,利用AC自动机建 trie 图之后,构建可达矩阵,可达矩阵 m 次方后,第一行的值就是答案。需要注意,这个题的答案很大,需要用到高精度,所以把高精度跟矩阵乘法结合即可。

如果单纯只是这样的话,先会 re 然后再 t,wa 是因为读入的字符串的范围是\([33,255]\),所以不能单纯用数组来存,需要用 map 来进行保存。

此外因为高精度乘法,再加上\(n^3\)的矩阵乘法,导致复杂度过大,所以会 t。观察发现,我们只用到了 ans 矩阵的第一行,所以可以只计算第一行的值即可,这样矩阵乘法就少了一个 n 的复杂度。

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#define mst(name, value) memset(name,value,sizeof(name))
using namespace std;


int MAXN=9999;
const int maxsize=30;
int dlen=4;
class BigNum {
public:
    int a[maxsize];
    int len;
public:
    BigNum() {
        len = 1;
        memset(a,0,sizeof(a));
    }
    BigNum(const int b) {
        int c,d = b;
        len = 0;
        memset(a,0,sizeof(a));
        while (d > MAXN) {
            c = d - (d / (MAXN + 1)) * (MAXN + 1);
            d = d / (MAXN + 1);
            a[len++] = c;
        }
        a[len++] = d;
    }
    BigNum operator+(const BigNum & T) const {
        BigNum t(*this);
        int i,big;
        big = T.len > len ? T.len : len;
        for (i = 0 ; i < big ; i++) {
            t.a[i] +=T.a[i];
            if (t.a[i] > MAXN) {
                t.a[i + 1]++;
                t.a[i] -=MAXN+1;
            }
        }
        if (t.a[big] != 0) t.len = big + 1;
        else t.len = big;
        return t;
    }
    BigNum operator*(const BigNum & T) const {
        BigNum ret;
        int i,j,up,temp,temp1;
        for (i = 0 ; i < len ; i++) {
            up = 0;
            for (j = 0 ; j < T.len ; j++) {
                temp = a[i] * T.a[j] + ret.a[i + j] + up;
                if (temp > MAXN) {
                    temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);
                    up = temp / (MAXN + 1);
                    ret.a[i + j] = temp1;
                } else {
                    up = 0;
                    ret.a[i + j] = temp;
                }
            }
            if (up != 0)
                ret.a[i + j] = up;
        }
        ret.len = i + j;
        while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }


};
ostream& operator<<(ostream& out,BigNum& b) {
    int i;
    cout<<b.a[b.len-1];
    for(i=b.len-2; i>=0; --i) {
        cout.width(dlen);
        cout.fill('0');
        cout<<b.a[i];
    }
    return out;
}
typedef vector<BigNum> vec;
typedef vector<vec> mat;

mat operator *(mat &a,mat &b){
    mat ans(a.size(),vec(b[0].size(),0));
    for(int i=0;i<=0;++i)
        for(int j=0;j<b[0].size();++j)
            for(int k=0;k<b.size();++k)
                ans[i][j]=ans[i][j]+a[i][k]*b[k][j];
    return ans;
}

const int maxn=105;
namespace ac {
    const int chsiz=300;
    int fail[maxn],end[maxn];
    map<char,int> next[maxn];
    int root,sz;
    int newcode(char s[],int &slen) {
        for(int i=0; i<slen; ++i)
            next[sz][s[i]]=-1;
        end[sz++]=0;
        return sz-1;
    }
    void init(char s[],int &slen) {
        sz=0;
        root=newcode(s,slen);
    }
    void insert(char buf[],char s[],int &slen) {
        int len=strlen(buf);
        int now=root;
        for(int i=0; i<len; ++i) {
            if(next[now][buf[i]]==-1)
                next[now][buf[i]]=newcode(s,slen);
            now=next[now][buf[i]];
        }
        end[now]++;
    }
    void build(char s[],int &slen) {
        queue<int> q;
        fail[root]=root;
        for(int i=0; i<slen; ++i) {
            if(next[root][s[i]]==-1)
                next[root][s[i]]=root;
            else {
                fail[next[root][s[i]]]=root;
                q.push(next[root][s[i]]);
            }
        }
        while(q.size()) {
            int now=q.front();
            q.pop();
            end[now]|=end[fail[now]];
            for(int i=0; i<slen; ++i) {
                if(next[now][s[i]]==-1)
                    next[now][s[i]]=next[fail[now]][s[i]];
                else {
                    fail[next[now][s[i]]]=next[fail[now]][s[i]];
                    q.push(next[now][s[i]]);
                }
            }
        }
    }
    mat getmat(char s[],int &slen) {
        mat ans(sz,vec(sz,0));
        for(int i=0; i<sz; ++i) {
            for(int j=0; j<slen; ++j)
                if(!end[next[i][s[j]]])
                    ans[i][next[i][s[j]]]=ans[i][next[i][s[j]]]+1;
        }
        return ans;
    }
}

char s[maxn],buf[maxn];
int main() {
    int n,m,p;
    scanf("%d%d%d",&n,&m,&p);
    scanf("%s",s);
    ac::init(s,n);
    for(int i=1; i<=p; ++i) {
        scanf("%s",buf);
        ac::insert(buf,s,n);
    }
    ac::build(s,n);
    mat k=ac::getmat(s,n);

    mat ans=k;
    for(int i=1;i<m;++i)
        ans=ans*k;
    BigNum sum=0;
    for(int i=0; i<ac::sz; ++i)
        sum=sum+ans[0][i];
    cout<<sum<<endl;

    return 0;
}
posted @ 2020-12-03 19:46  caoanda  阅读(223)  评论(0编辑  收藏  举报