用ac自動機處理所有了解的單詞
顯然,不能直接算,直接算的話,我們需要大力容斥,複雜度不允許
我們不妨反過來做,我們根據ac自動機處理出所有的不可行解,然後用總數減去即可
計算所有不可行解用dp,\(f[i][j]\)表示處理到字串第i位,在自動機上第j個節點的不可行方案數,直接暴力轉移即可
#include#include#include#include#includeusing namespace std;
const int sigma_size = 26;
const int maxnode = 11000;
const int maxs = 150 + 10;
struct ahocorasickautomata
// 字元c的編號
int idx(char c)
// 插入字串。v必須非0
void insert(char *s, int v)
u = ch[u][c];
}val[u] = v;
} // 遞迴列印以結點j結尾的所有字串
void print(int j)
} // 在t中找模板
int find(char* t)
} // 計算fail函式
void getfail()
}// 按bfs順序計算fail
while(!q.empty())
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];}}
/* *when matrix need
for(int i = 0; i < sz; i++)
*//* 統計長度為n的串有多種可能不出現模板串,需要matrix
int doit(int n)
}a = a ^ n;
int ans = 0;
for(int i = 0; i < sz; i++)
return ans;}*/
}};ahocorasickautomata ac;
char p[80][1100];
int n,m,t,f[110][maxnode];
const int mo=10007;
int dp()
int res=0;
for (int i=0;i<=ac.sz;i++)
res=(res+f[m][i])%mo;
return res;
}int main()
ac.getfail();
int res=dp(),ans=1;
for (int i=1;i<=m;i++)
ans=ans*26%mo;
printf("%d\n",(ans+mo-res)%mo);
return 0;
}
JSOI2007 文字生成器
容斥原理,求出所有的情況減去不可讀的情況就是可讀的文字數了a 找不可讀文字的數量類似於病毒那一題趴我覺得 dp轉移的話.用f i j 表示當前在節點j,且串長為i時的情況 include using namespace std const int mod 1e4 7 const int n 2000...
JSOI2007 文字生成器
對於乙個長度為 n 的串 s 有多少可能情況的串 s 使得 s 的子串中至少包含乙個給定的串,給定的串有 m 個 由多模式串匹配想到ac自動機,由計數想到dp 首先建好trie圖,更新所有end標記。記 dp now st flag 表示當前正在匹配第 st 位,已確定的串匹配到了trie圖上的 n...
JSOI2007 文字生成器
ac 機上的計數 dp 啊 並沒有想到反著求出不合法的串的個數,直接正面硬上 設 dp i j 0 1 表示匹配出的長度為 i 在 ac 機上位置為 j 沒有 有匹配到乙個完整串的方案數 由於這個的長度是滿足子結構的,可以直接 dp 求解 注意結束標記會影響到所有能通過跳 fail 到達它的點,所以...