poj--1625Censored!+AC自動機上的dp+大數
題目連結:點選進入
其實看起來是完全可以用矩陣做的,但是因為用到了大數的,導致記憶體開不下,所以用dp寫了。其實dp的過程依舊就是在我們用禁止出現單詞構建的trie上走m步的過程。我們定義dp[i][j]表示走過i步以後到達節點j的方案數,則狀態轉移應該是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的節點,並且不能是病毒節點。但是其實這樣程式碼就不是那麼好寫了,其實我們可以用節點j主動的去更新它的子節點k,這樣轉移方程就成了dp[i][next[j][k]]+=dp[i-1][j]。要求next[j][k]不能使病毒節點。總而言之,AC自動機上的dp就是要利用我們建立的trie樹以及上面的轉移方式進行狀態轉移。
程式碼如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
///大數模版
struct BigInteger{
int A[25];
enum{MOD = 10000};
BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
void print(){
printf("%d", A[A[0]]);
for (int i=A[0]-1; i>0; i--){
if (A[i]==0){printf("0000"); continue;}
for (int k=10; k*A[i]<MOD; k*=10) printf("0");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int p) {return A[p];}
const int& operator [] (int p) const {return A[p];}
BigInteger operator + (const BigInteger& B){
BigInteger C;
C[0]=max(A[0], B[0]);
for (int i=1; i<=C[0]; i++)
C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
if (C[C[0]+1] > 0) C[0]++;
return C;
}
BigInteger operator * (const BigInteger& B){
BigInteger C;
C[0]=A[0]+B[0];
for (int i=1; i<=A[0]; i++)
for (int j=1; j<=B[0]; j++){
C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
}One;
const int maxn=10*10+5;
char alph[maxn];
map<char,int>h;
int getIndex(char ch)
{
return h[ch];
}
struct Trie
{
int next[maxn][maxn/2],fail[maxn],flag[maxn];
int root,L,len;
int newnode()
{
memset(next[L],-1,sizeof(next[L]));
flag[L++];
return L-1;
}
void init()
{
L=0;
root=newnode();
}
void insert(char buf[])
{
int len1=strlen(buf);
int now=root;
for(int i=0;i<len1;i++)
{
int index=getIndex(buf[i]);
if(next[now][index]==-1)
next[now][index]=newnode();
now=next[now][index];
}
flag[now]=1;
}
void build()
{
queue<int>Q;
fail[root]=root;
for(int i=0;i<len;i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty())
{
int now=Q.front();
if(flag[fail[now]])
flag[now]++;
Q.pop();
for(int i=0;i<len;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
//flag[next[now][i]]|=flag[next[fail[now]][i]];
Q.push(next[now][i]);
}
}
}
}
};
Trie ac;
char str[maxn];
BigInteger dp[maxn][maxn];
int main()
{
int n,m,p;
///freopen("in.txt","r",stdin);
One.set(1);
while(scanf("%d%d%d",&n,&m,&p)!=EOF)
{
h.clear();
scanf("%s",alph);
for(int i=0;i<strlen(alph);i++)
h[alph[i]]=i;
ac.init();
ac.len=strlen(alph);
for(int i=0;i<p;i++)
{
scanf("%s",str);
ac.insert(str);
}
ac.build();
for(int i=0;i<=m;i++)
for(int j=0;j<ac.L;j++)
dp[i][j].set(0);
dp[0][0].set(1);
for(int i=1;i<=m;i++)
for(int j=0;j<ac.L;j++)
for(int k=0;k<n;k++)
{
if(ac.flag[ac.next[j][k]]) continue;
dp[i][ac.next[j][k]]=dp[i][ac.next[j][k]]+dp[i-1][j];
}
BigInteger ans;
ans.set(0);
for(int i=0;i<ac.L;i++)
ans=ans+dp[m][i];
ans.print();
}
return 0;
}
相關文章
- [複習] AC自動機
- AC自動機 提高篇
- AC自動機:Tire樹+KMPKMP
- 簡單版AC自動機
- AC 自動機學習筆記筆記
- AC自動機學習筆記筆記
- AC 自動機——多模式串匹配模式
- 專題十七 AC自動機【Kuangbin】
- AC自動機+字典序+樹狀陣列陣列
- 從零開始發明 AC 自動機
- hdu2222--Keywords Search+AC自動機模板
- 自研AC配置(上電過程)
- Aho-Corasick 演算法 AC自動機實現演算法
- hdu-5384Danganronpa+多校訓練+AC自動機
- AC自動機+trie樹實現高效多模式匹配字典模式
- 自研AP配置(上電發現AC)
- poj--2778DNA Sequence+AC自動機+矩陣快速冪矩陣
- 巨大的數(dp+矩陣加速)矩陣
- hdu 1277 AC自動機入門(指標版和陣列版)指標陣列
- OracleLinux上的Oracle開關機自啟動OracleLinux
- 幸運數(dp+矩陣加速)矩陣
- HanLP — Aho-Corasick DoubleArrayTire 演算法 ACDAT - 基於雙陣列字典樹的AC自動機HanLP演算法陣列
- 牛客周賽 Round50 E-小紅的樹上移動 (期望dp+逆元)
- AC86U kx上網
- 傑裡之AC696N 的藍芽連線成功自動播放【篇】藍芽
- SOLIDWORK自動化引數在傳送帶上的應用Solid
- ac79啟動流程
- 四大自動駕駛場景,誰勝出的機率大?自動駕駛
- 約瑟夫問題,輸入總人數,自動產生大於0小於n的隨機數隨機
- 自動機
- 電腦開機自動撥號上網怎麼設定?電腦自動撥號上網的設定方法步驟
- KMP 自動機KMP
- BOSHIDA AC/DC電源模組:應用於工業自動化領域
- 7寸串列埠屏在小型自動售貨機上的應用串列埠
- HyperSnips:VSCode上的自動補全神器VSCode
- 傑裡之AC695 耳機 V016 版本對於 DCDC 的關機功耗大問題【篇】
- AC-DMIS 5.3 V變數賦值變數賦值
- win10開機怎麼自動撥號_win10怎麼自動撥號上網Win10