JSOI2007 文字生成器

2022-03-03 02:50:36 字數 1539 閱讀 7014

用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 到達它的點,所以...