1. 程式人生 > 實用技巧 >【題解】薇爾莉特的打字機

【題解】薇爾莉特的打字機

題目地址:here

首先,這題需要處理字串,我們用 trie分析

先忽略刪除操作

拿樣例 1 舉個例子:

首先把最開始的字串插入到樹中

然後薇爾莉特打了一個字元 A
此時可以插入或者是不插入,就會有這樣的情況:

不插入時,之前插入進去的字元均可以作為字串的結尾

假設之前插入了 x個字母,每一個字母都可以作為串的結尾

現在插入這個字元,總數似乎又增加了 x個

繼續看樣例 1,此時薇爾莉特又打了一個字元 A
此時把它插入樹中,就是這樣:

此時能作為串的結尾的數仍然只有 A,重複了

所以如果新產生的可以作為結尾的節點

那麼沒有可以作為結尾的節點和這個節點相同

可能說的有點繞,舉個例子:

假如 A已經存在於這棵樹中並且可以作為結尾

那麼再插入一個 A不能增加可以作為結尾節點的數量

令 ans表示插入之前可以作為結尾節點的節點數量

新插入的字元為 x
fi表示已經有第 i種字元的可以作為結尾節點的總數

我們可以算出現在的 ans=之前的 ans×2-fch,fch=原來的 ans
接下來是刪除部分

此時我們已經插入了這幾個節點:

刪除的過程其實就是去掉當前節點往上跳的過程

比如說刪除當前的 A之後就是這樣:

刪除了這個節點往上跳,上面的節點一定是可以作為結尾節點的節點

所以此時新產生的結果只有 1,加 1 即可

模擬 trie的操作,直接遞推就好了

PS:道路我都懂,可是為什麼模數是這麼奇怪的數(可能是我太菜了,還不懂什麼意思)

AC程式碼:

#include <bits/stdc++.h>
using namespace std;
const int mod = 19260817;
int n, m;
int f[100];
char s[5000002];
int main() {
    cin >> n >> m;
    scanf("%s", s + 1);
    char ch;
    int ans = 1;
    while (m--) {
        cin >> ch;
        if (ch == 'u') {  //刪除操作
            if (!n)
                continue;  //沒有可以刪除的了
            else {
                ans = (ans + 1) % mod;                      //+1
                f[s[n] - 'A'] = (f[s[n] - 'A'] + 1) % mod;  //+1
                --n;  //刪除節點往上跳
            }
        } else {
            int tmp = f[ch - 'A'];                        //暫時儲存
            f[ch - 'A'] = ans;                            //賦值
            ans = ((ans + ans - tmp) % mod + mod) % mod;  //算 ans
        }
    }
    cout << ans;
    return 0;
}