標籤:style blog http color os io for ar
UVA 1519 - Dictionary Size
題目連結
題意:有一個字典,裡麵包含一些詞,要求組合新詞,新詞必須來自原字典,或者由原字典的字串的非空首碼和非空尾碼組成,問一共能組成多少個新詞
思路:建Trie樹,可以求出不同的首碼和尾碼個數,然後相乘,這樣做會有一部分重複的
比如Aaaa,aaaA的情況,就重複了,去重的方法可以推理出來
假設首碼A後面有x個a,尾碼y個a後面一個A,那麼這x和y個一共一邊各有(x+1)和(y+1)種情況,相乘一共是(x+1)(y+1)種,那麼實際上一共只能組成1 + x + y(比如上面的例子,一共就能組成空串,a, aa, aaa, aaaa, aaaaa, aaaaaa種)這樣減掉就得到x*y,這樣一來只要在建Trie的過程中,記錄下每種字元各出現多少個就能算了(注意開頭的單獨一個不能算,因為要非空),然後還有一點要注意的,就是長度為1的字串,由於題目單詞可以來自原字典,而長度1的字串在計算過程並沒有算進去,所以還要單獨出來算
代碼:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXNODE = 400005;const int SIGMA_SIZE = 26;struct Trie { int ch[MAXNODE][SIGMA_SIZE]; int cnt[SIGMA_SIZE]; int sz; void init() {sz = 1;memset(ch[0], 0, sizeof(ch[0]));memset(cnt, 0, sizeof(cnt)); } int idx(char c) {return c - 'a'; } void insert(char *s) {int n = strlen(s);int u = 0, v;for (int i = 0; i < n; i++) { int c = idx(s[i]); if (!ch[u][c]) {memset(ch[sz], 0, sizeof(ch[sz]));ch[u][c] = sz++;if (i) cnt[c]++; } u = ch[u][c];} }}pre, suf;typedef long long ll;int n, vis[26];char str[45];int main() { while (~scanf("%d", &n)) {pre.init(); suf.init();memset(vis, 0, sizeof(vis));while (n--) { scanf("%s", str); if (strlen(str) == 1)vis[str[0] - 'a'] = 1; pre.insert(str); reverse(str, str + strlen(str)); suf.insert(str);}ll ans = (ll)(pre.sz - 1) * (suf.sz - 1);for (int i = 0; i < 26; i++) ans -= (ll)pre.cnt[i] * suf.cnt[i] - vis[i];printf("%lld\n", ans); } return 0;}