魔法咒語

魔法咒語

題目描述

Chandra 是一個魔法天才。從一歲時接受火之教會洗禮之後, Chandra 就顯示出對火元素無與倫比的親和力,輕而易舉地學會種種晦澀難解的法術。這也多虧 Chandra 有着常人難以企及的語言天賦,讓她能輕鬆流利地說出咒語中那些極其拗口的魔法詞彙。直到十四歲,開始學習威力強大的禁咒法術時, Chandra 才遇到了障礙。

根據火之魔法規則,禁咒的構成單位是 NN 個基本詞彙。施法時只要凝聚精神力,說出一段用這些詞語組成的長度恰好等於 LL 的語言,就能釋放威力超乎想象的火法術。過去的魔法師們總結了幾種表達起來最連貫的組合方式,方便施法者以最快語速完成法術。但具有魔法和語言雙重天才的 Chandra 不滿足於這幾種流傳下來的禁咒,因爲她可以毫無困難地說出普通人幾乎不可能表達的禁咒語句。然而,在實際施法時, Chandra 發現有些自創禁咒念出後不但沒有預期效果,反而會使自己的精神力迅速枯竭,十分難受。這個問題令 Chandra 萬分不解。她大量閱讀典籍,到處走訪魔法學者,並且不顧精神折磨一次又一次嘗試新咒語,希望找出問題的答案。很多年過去了,在一次遠古遺蹟探險中, Chandra 意外闖進了火之神艾利克斯的不知名神殿。根據岩土特徵分析,神殿應該有上萬年的歷史,這是極其罕見的。 Chandra 小心翼翼地四處探索,沿着魔力流動來到一間密室。她看見密室中央懸浮着一本書籍。在魔法保護下書籍狀況完好。精通上古語言的 Chandra 讀過此書,終於解開了多年的困惑。禁咒法術之所以威力強大,是因爲咒語借用了火之神艾利克斯的神力。這本書裏記載了艾利克斯生平忌諱的 M 個詞語,比如情敵的名字、討厭的植物等等。

使用禁咒法術時,如果語言中含有任何忌諱詞語,就會觸怒神力而失效,施法者也一併遭受懲罰。例如,若 ”banana” 是唯一的忌諱詞語, “an”、 ”ban”、 ”analysis” 是基本詞彙,禁咒長度須是 11, 則“bananalysis” 是無效法術, ”analysisban”、 ”anbanbanban”是兩個有效法術。注意:一個基本詞彙在禁咒法術中可以出現零次、 一次或多次;只要組成方式不同就認爲是不同的禁咒法術,即使書寫形式相同。謎題破解, Chandra 心情大好。她決定計算一共有多少種有效的禁咒法術。由於答案可能很大,你只需要輸出答案模 1,000,000,007的結果。


Sol

 

把禁咒建AC自動機,預處理每一個基本詞彙從每一個點開始跑會跑到哪,會不會碰到禁咒。
然後第一問暴力dp,第二問蒟乘
注意對於一個串,如果他的fail是禁咒,那麼他也是非法點
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#define maxn 105
#define mod 1000000007
#define ll long long
using namespace std;
int n,N,m,l,tr[maxn][26],fail[maxn],p[maxn],tot,cnt,head[maxn];
int f[maxn][105];
string a[maxn];
char ch[maxn];
struct node{
    int v,nex,w;
}e[1000005];
void ins(){
    int len=strlen(ch),k=0;
    for(int i=0;i<len;i++){
        if(!tr[k][ch[i]-'a'])tr[k][ch[i]-'a']=++cnt;
        k=tr[k][ch[i]-'a'];
    }
    p[k]=1;
}
void build(){
    queue<int>q;
    for(int i=0;i<26;i++)if(tr[0][i])q.push(tr[0][i]);
    while(!q.empty()){
        int k=q.front();q.pop();
        for(int i=0;i<26;i++){
            if(tr[k][i]){
                fail[tr[k][i]]=tr[fail[k]][i];
                p[tr[k][i]]|=p[tr[fail[k]][i]]; 
                q.push(tr[k][i]);
            }
            else tr[k][i]=tr[fail[k]][i];
        }
    }
    
}
void add(int t1,int t2,int t3){
    e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
}
struct no{
    ll v[505][505];
}s,A;
no operator *(no a,no b){
    no c;
    for(int i=0;i<=N;i++)
    for(int j=0;j<=N;j++){
        c.v[i][j]=0;
        for(int k=0;k<=N;k++){
            c.v[i][j]=(c.v[i][j]+1LL*a.v[i][k]*b.v[k][j]%mod)%mod;
        }
    }
    return c;
}
int main()
{
    cin>>n>>m>>l;
    for(int i=1;i<=n;i++){
        scanf("%s",ch);
        a[i]=(string)ch;
    }
    for(int i=1;i<=m;i++){
        scanf("%s",ch);ins();
    }
    build();
    for(int i=0;i<=cnt;i++){
        
        for(int j=1;j<=n;j++){
            int k=i,fl=0;if(p[k])continue;
            for(int x=0;x<a[j].size();x++){
                k=tr[k][a[j][x]-'a'];
                if(p[k]){fl=1;break;}
            }
            if(fl)continue;
            add(i,k,a[j].size());
        }
        
    }
    
    if(l<=100){
    f[0][0]=1;
    for(int x=0;x<=l;x++){
        for(int k=0;k<=cnt;k++){
            for(int i=head[k];i;i=e[i].nex){
                if(e[i].w+x>l)continue;
                f[e[i].v][x+e[i].w]=(f[e[i].v][x+e[i].w]+f[k][x])%mod;
            }
        }
    }
    int ans=0;
    for(int i=0;i<=cnt;i++)ans=(ans+f[i][l])%mod;
    cout<<ans<<endl;
    return 0;
    }
    N=cnt+cnt+1;
    for(int k=0;k<=cnt;k++){
        s.v[k+cnt+1][k]++;
        for(int i=head[k];i;i=e[i].nex){
            int j=e[i].v;
            if(e[i].w==1)s.v[k][j]++;
            else s.v[k][j+cnt+1]++;
        }
    }
    for(int i=0;i<=N;i++)A.v[i][i]=1;
    while(l){
        if(l&1)A=A*s;
        s=s*s;l>>=1;
    }
    ll ans=0;
    for(int i=0;i<=cnt;i++){
        ans=(ans+A.v[0][i])%mod;
    }
    cout<<ans<<endl;
    
    return 0;
}
View Code

 

posted @ 2019-04-07 21:19 liankewei123456 閱讀(...) 評論(...) 編輯 收藏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章