ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[BJOI2017]魔法咒语

2019-03-06 21:50:54  阅读:287  来源: 互联网

标签:10 ch int 魔法 BJOI2017 法术 禁咒 Chandra 咒语


Description
Chandra 是一个魔法天才。

从一岁时接受火之教会洗礼之后, Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术。这也多亏 Chandra 有着常人难以企及的语言天赋,让她能轻松流利地说出咒语中那些极其拗口的魔法词汇。

直到十四岁,开始学习威力强大的禁咒法术时, Chandra 才遇到了障碍。

根据火之魔法规则,禁咒的构成单位是 N 个基本词汇。施法时只要凝聚精神力,说出一段用这些词语组成的长度恰好等于 L 的语言,就能释放威力超乎想象的火法术。过去的魔法师们总结了几种表达起来最连贯的组合方式,方便施法者以最快语速完成法术。

但具有魔法和语言双重天才的 Chandra 不满足于这几种流传下来的禁咒,因为她可以毫无困难地说出普通人几乎不可能表达的禁咒语句。然而,在实际施法时, Chandra 发现有些自创禁咒念出后不但没有预期效果,反而会使自己的精神力迅速枯竭,十分难受。

这个问题令 Chandra 万分不解。她大量阅读典籍,到处走访魔法学者,并且不顾精神折磨一次又一次尝试新咒语,希望找出问题的答案。

很多年过去了,在一次远古遗迹探险中, Chandra 意外闯进了火之神艾利克斯的不知名神殿。根据岩土特征分析,神殿应该有上万年的历史,这是极其罕见的。 Chandra 小心翼翼地四处探索,沿着魔力流动来到一间密室。她看见密室中央悬浮着一本书籍。在魔法保护下书籍状况完好。精通上古语言的 Chandra 读过此书,终于解开了多年的困惑。

禁咒法术之所以威力强大,是因为咒语借用了火之神艾利克斯的神力。这本书里记载了艾利克斯生平忌讳的 M 个词语,比如情敌的名字、讨厌的植物等等。使用禁咒法术时,如果语言中含有任何忌讳词语,就会触怒神力而失效,施法者也一并遭受惩罚。

例如,若 ”banana” 是唯一的忌讳词语, “an”、 ”ban”、 ”analysis” 是基本词汇,禁咒长度须是 11, 则“bananalysis” 是无效法术, ”analysisban”、 ”anbanbanban”是两个有效法术。注意:一个基本词汇在禁咒法术中可以出现零次、 一次或多次;只要组成方式不同就认为是不同的禁咒法术,即使书写形式相同。

谜题破解, Chandra 心情大好。她决定计算一共有多少种有效的禁咒法术。

由于答案可能很大,你只需要输出答案模 1,000,000,007的结果。

Input
第一行,三个正整数 N, M, L。
接下来 N 行,每行一个只含小写英文字母的字符串,表示一个基本词汇。
接下来 M 行,每行一个只含小写英文字母的字符串,表示一个忌讳词语。
对于60%的数据1<=N,M<=50,L<=100
对于另40%数据基本词汇长度不超过2,L<=10^8

Output
仅一行,一个整数,表示答案(模 10^9+7)。

Sample Input
4 2 10
boom
oo
ooh
bang
ob
mo

Sample Output
14


BJOI的题感觉就是疯狂分类讨论(一题更比两题强)

首先考虑60%的数据,对禁忌串建立AC自动机,然后设\(f[i][j]\)表示长度为\(i\),匹配到AC自动机的第\(j\)个位置的方案数,转移的时候则需要枚举基本词汇,判断其从\(j\)开始匹配时是否会出现禁忌词汇,否则记匹配完后的位置为\(k\),由\(f[i][j]\)转移到\(f[i+len][k]\)即可

考虑len=1的部分,那么\(f[i][j]\)必然会转移到\(f[i+1][k]\),那么我们就可以用矩阵乘法加速转移,具体而言,如果\(f[i][j]\)可以转移到\(f[i+1][k]\),则转移矩阵\(Tr[j][k]\)加1即可

考虑len=2的部分,类比一下我们求Fibonacci数列时使用的矩阵,同样的,我们记录两个信息,表示\(f[0],f[1]\)(第二维我就不写了),那么转移矩阵就自己画图弄一弄吧

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1;char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e2,Mod=1e9+7;
int n,m,L;
char S[N+10][N+10];
struct S1{
    int trie[N+10][26],fail[N+10],tot,root;
    bool End[N+10];
    void insert(char *s){
        int len=strlen(s),p=root;
        for (int i=0;i<len;i++){
            if (!trie[p][s[i]-'a']) trie[p][s[i]-'a']=++tot;
            p=trie[p][s[i]-'a'];
        }
        End[p]=1;
    }
    void make_fail(){
        static int h[N+10];
        int head=1,tail=0;
        for (int i=0;i<26;i++)  if (trie[root][i])  h[++tail]=trie[root][i];
        for (;head<=tail;head++){
            int Now=h[head];
            End[Now]|=End[fail[Now]];
            for (int i=0;i<26;i++){
                if (trie[Now][i]){
                    int son=trie[Now][i];
                    fail[son]=trie[fail[Now]][i];
                    h[++tail]=son;
                }else   trie[Now][i]=trie[fail[Now]][i];
            }
        }
    }
    int check(char *s,int Fir){
        int len=strlen(s),p=Fir;
        for (int i=0;i<len;i++){
            p=trie[p][s[i]-'a'];
            if (End[p]) return -1;
        }
        return p;
    }
}AC;//Aho-Corasick automaton
namespace DP{
    int f[N+10][N+10];
    void main(){
        f[0][0]=1;
        for (int i=0;i<L;i++){
            for (int j=0;j<=AC.tot;j++){
                if (!f[i][j])   continue;
                for (int k=1;k<=n;k++){
                    int tmp=AC.check(S[k],j),len=strlen(S[k]);
                    if (!~tmp||i+len>L) continue;
                    f[i+len][tmp]=(f[i+len][tmp]+f[i][j])%Mod;
                }
            }
        }
        int Ans=0;
        for (int i=0;i<=AC.tot;i++) Ans=(Ans+f[L][i])%Mod;
        printf("%d\n",Ans);
    }
};
namespace Matrix{
    int T;
    struct Matrix{
        int v[(N<<1)+10][(N<<1)+10];
        Matrix(){memset(v,0,sizeof(v));}
        void init(){for (int i=0;i<T;i++)   v[i][i]=1;}
    }Trans;
    Matrix operator *(const Matrix &x,const Matrix &y){
        Matrix z;
        for (int i=0;i<T;i++)
            for (int j=0;j<T;j++)
                for (int k=0;k<T;k++)
                    z.v[i][k]=(1ll*x.v[i][j]*y.v[j][k]+z.v[i][k])%Mod;
        return z;
    }
    Matrix mlt(Matrix a,int b){
        Matrix res; res.init();
        for (;b;b>>=1,a=a*a)    if (b&1)    res=res*a;
        return res;
    }
    void main(){
        Matrix Ans; Ans.v[0][0]=1; T=(AC.tot<<1)+2;
        for (int i=0;i<=AC.tot;i++) Trans.v[AC.tot+1+i][i]=1;
        for (int i=0;i<=AC.tot;i++){
            for (int j=1;j<=n;j++){
                int tmp=AC.check(S[j],i),len=strlen(S[j]);
                if (!~tmp)  continue;
                if (len==1){
                    Trans.v[i+AC.tot+1][tmp+AC.tot+1]++;
                    if (!i) Ans.v[0][tmp+AC.tot+1]++;
                }else   Trans.v[i][tmp+AC.tot+1]++;
            }
        }
        Ans=Ans*mlt(Trans,L);
        int res=0;
        for (int i=0;i<=AC.tot;i++) res=(res+Ans.v[0][i])%Mod;
        printf("%d\n",res);
    }
};
int main(){
    n=read(),m=read(),L=read();
    for (int i=1;i<=n;i++)  scanf("%s",S[i]);
    for (int i=1;i<=m;i++){
        static char s[N+10];
        scanf("%s",s);
        AC.insert(s);
    }
    AC.make_fail();
    if (L<=1e2){
        DP::main();
        return 0;
    }
    Matrix::main();
    return 0;
}

标签:10,ch,int,魔法,BJOI2017,法术,禁咒,Chandra,咒语
来源: https://www.cnblogs.com/Wolfycz/p/10486282.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有