日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

day16T2改错记

發布時間:2025/7/14 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 day16T2改错记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給出\(n\)個串,你要從每個串中抽出一個子串(可以是空串),把他們拼接起來,問:

  • 按字典序輸出所有可能的結果(包括空串)
  • 輸出總共有多少種不同的結果(包括空串),對\(1e9+7\)取模
  • 最后輸入一個\(k\),為\(0\)時只回答第二問,為\(1\)時回答兩個問

    保證輸入不超過\(1MB\),輸出不超過\(200MB\)(就是說第二問真實值很大時不會要求回答第一問)

    解析

    要取出子串,容易想到后綴自動機

    于是對每個串建出后綴自動機

    然后考慮怎么表示“拼接”

    不難發現,如果后面某個串中存在的字符可以在當前這個自動機內轉移到,那么取后者不會漏掉任何結果,所以我們只用管每個節點在自己的自動機內轉移不到的字符

    即只有當不能在自己的串中轉移時才考慮拼接后面的串

    假設某個節點\(u\)沒有轉移到\(c\)的邊,那么我們找到它后面的自動機中第一個能轉移到\(c\)的根節點\(rt\),從\(u\)\(rt->trans[c]\)拉一條邊,這樣就表示了“拼接”的過程

    第一問就從第一個串的根節點開始貪心地\(dfs\),過程中輸出即可,此處可以信仰一波不會\(TLE\),不然光輸出就\(GG\)了,想來不會有這種數據……

    第二問就是問路徑數了,拓撲排序\(dp\)即可

    代碼

    為什么貼的是\(70pts\)代碼呢?因為有\(3\)組數據輸出實在太長,\(OJ\)判了所有人\(OLE\)……

    #include <cstdio> #include <iostream> #include <queue> #include <cstring> #include <algorithm> #define MAXN 1000005typedef long long LL; const int mod = (int)1e9 + 7; const char set[] = {'A', 'C', 'G', 'T'}; struct SAM {int idx, cnt, last, root[MAXN], next[MAXN << 1][4], link[MAXN << 1], maxlen[MAXN << 1], deg[MAXN << 1], top, dp[MAXN << 1];bool vis[MAXN << 1]; char cur[MAXN << 1];int newnode(int = 0);int add(int);void insert(char *);void prework();void prework(int, int);void dfs(int);void bfs(); };int N, K; char str[MAXN]; SAM sam; int ans;inline void inc(int &x, int y) { x += y; if (x >= mod) x -= mod; } inline void dec(int &x, int y) { x -= y; if (x < 0) x += mod; } inline int add(int x, int y) { x += y; return x >= mod ? x - mod : x; } inline int sub(int x, int y) { x -= y; return x < 0 ? x + mod : x; }int main() {freopen("copy.in", "r", stdin);freopen("copy.out", "w", stdout);scanf("%d", &N);for (int i = 1; i <= N; ++i) {scanf("%s", str);sam.insert(str);}scanf("%d", &K);sam.prework();if (K) sam.dfs(sam.root[1]);sam.bfs();printf("%d\n", ans);return 0; } int SAM::newnode(int x) {++idx;if (x) {link[idx] = link[x], maxlen[idx] = maxlen[x];for (int i = 0; i < 4; ++i) next[idx][i] = next[x][i];}return idx; } int SAM::add(int c) {int np = newnode(), p = last;maxlen[np] = maxlen[last] + 1;while (p && !next[p][c]) next[p][c] = np, p = link[p];if (!p) link[np] = root[cnt];else {int q = next[p][c];if (maxlen[q] == maxlen[p] + 1) link[np] = q;else {int nq = newnode(q);maxlen[nq] = maxlen[p] + 1;link[q] = link[np] = nq;while (p && next[p][c] == q) next[p][c] = nq, p = link[p];}}return np; } void SAM::insert(char *s) {int n = strlen(s); last = root[++cnt] = newnode();for (int i = 0; i < n; ++i) last = add(std::lower_bound(set, set + 4, s[i]) - set); } void SAM::prework() {for (int i = cnt; i; --i) prework(root[i], root[i + 1]);for (int i = 1; i <= idx; ++i) for (int j = 0; j < 4; ++j) ++deg[next[i][j]];for (int i = 2; i <= cnt; ++i) for (int j = 0; j < 4; ++j) --deg[next[root[i]][j]]; } void SAM::prework(int x, int y) {if (vis[x]) return;vis[x] = 1;for (int i = 0; i < 4; ++i)if (!next[x][i]) next[x][i] = next[y][i];else prework(next[x][i], y); } void SAM::dfs(int x) {cur[top] = '\0';printf("%s\n", cur);for (int i = 0; i < 4; ++i)if (next[x][i]) {cur[top++] = set[i];dfs(next[x][i]);--top;} } void SAM::bfs() {static int q[MAXN << 1], hd, tl;q[tl++] = root[1], dp[root[1]] = 1;while (hd < tl) {int p = q[hd++];if (!p) continue;inc(ans, dp[p]);for (int i = 0; i < 4; ++i) {inc(dp[next[p][i]], dp[p]);if (!(--deg[next[p][i]])) q[tl++] = next[p][i];}} } //Rhein_E 70pts

    轉載于:https://www.cnblogs.com/Rhein-E/p/10560540.html

    總結

    以上是生活随笔為你收集整理的day16T2改错记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。