字串雜題準備
阿新 • • 發佈:2020-12-17
目錄
,考慮用倍增實現。
即可。
HDU 2243 考研路茫茫——單詞情結
考點:
\(AC\)自動機+矩乘
思路:
答案是\(\sum_{i=1}^L 26^i -不合法方案\)
考慮\(L\)的值很大,而\(N\)及\(len\)很小,可以由一種暴力的\(DP\)轉移想到在\(trie\)上面用矩乘實現優化。
考慮矩陣的編號就是\(trie\)上的每個點的編號,那麼轉移矩陣很容易得到,初始矩陣也容易得到,這樣不合法方案就可以用\(O(node^3*logL)\)解決。
考慮如何快速求\(\sum_{i=1}^L 26^i\),可以發現這是個多項式乘法的樣式,而且係數都為\(1\)
設\(cf[i]=2^i,cf_{26}[i]=26^{2^i},val[i]=\sum_{j=1}^{2^i} 26^j\),顯然這兩個都可以快速求得。
cf[0] = 1; fo(i, 1, 31) cf[i] = cf[i - 1] << 1;
cf_26[0] = val[0] = 26; fo(i, 1, 30) {
cf_26[i] = cf_26[i - 1] * cf_26[i - 1];
val[i] = val[i - 1] + cf_26[i - 1] * val[i - 1];
}
而後直接用倍增就可以求得\(\sum_{i=1}^L 26^i\)
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> #define N 110 #define maxn 10010 #define db double #define ll long long #define ull unsigned ll #define mem(x, a) memset(x, a, sizeof x) #define mpy(x, y) memcpy(x, y, sizeof y) #define fo(x, a, b) for (int x = (a); x <= (b); x++) #define fd(x, a, b) for (int x = (a); x >= (b); x--) #define go(x) for (int p = tail[x], v; p; p = e[p].fr) using namespace std; struct matrix{ int n, m; ull a[N][N]; matrix() {mem(a, 0); n = m = 0;} void clear() {mem(a, 0); n = m = 0;} matrix operator *(const matrix x) { matrix c; c.n = n, c.m = x.m; fo(k, 1, c.m) fo(i, 1, c.n) fo(j, 1, c.m) c.a[i][j] += a[i][k] * x.a[k][j]; return c; } }a, b, c; ll cf[32]; int n, m, trie[maxn][27]; int fail[maxn], dl[maxn], tot = 1; ull ans = 0, cf_26[32], val[32]; bool label[maxn]; char s[N]; vector<int> rev[maxn]; inline int read() { int x = 0, f = 0; char c = getchar(); while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar(); while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return f ? -x : x; } void clear() { fo(i, 1, tot) rev[i].clear(), mem(trie[i], 0), label[i] = 0; a.clear(), b.clear(); tot = 1; } void insert() { scanf("%s", s + 1); int len = strlen(s + 1), now = 1; fo(i, 1, len) { int t = s[i] - 'a'; if (! trie[now][t]) trie[now][t] = ++tot; now = trie[now][t]; } label[now] = 1; } void make_fail() { fo(i, 1, tot) { fo(j, 0, 25) { if (! trie[i][j]) continue; int res = i == 1 ? i : fail[i]; while (res > 1 && ! trie[res][j]) res = fail[res]; if (trie[res][j] && res != i) res = trie[res][j]; fail[trie[i][j]] = res; rev[res].push_back(trie[i][j]); } } int l = 0, r = 0; fo(i, 1, tot) if (label[i]) dl[++r] = i; while (l++ < r) { int x = dl[l]; fo(i, 0, 25) { if (! trie[x][i] || label[trie[x][i]]) continue; label[trie[x][i]] = 1, dl[++r] = trie[x][i]; } int len_ = rev[x].size() - 1; fo(i, 0, len_) { if (label[rev[x][i]]) continue; label[rev[x][i]] = 1, dl[++r] = rev[x][i]; } } } bool check() { ull res = 1, s = 0; fo(i, 1, m) res = res * 26, s += res; return s == ans; } void solve(int x) { ll now = 0; ull kk = 1; ans = 0; fd(i, 31, 0) if (now + cf[i] <= x) ans += kk * val[i], now += cf[i], kk = kk * cf_26[i]; /* if (! check()) { printf("wrong\n"); } */ } int main() { freopen("word.in", "r", stdin); freopen("word.out", "w", stdout); cf[0] = 1; fo(i, 1, 31) cf[i] = cf[i - 1] << 1; cf_26[0] = val[0] = 26; fo(i, 1, 30) { cf_26[i] = cf_26[i - 1] * cf_26[i - 1]; val[i] = val[i - 1] + cf_26[i - 1] * val[i - 1]; } while (scanf("%d%d", &n, &m) != EOF) { clear(); solve(m); fo(i, 1, n) insert(); make_fail(); a.n = 1, a.m = tot + 1; fo(i, 0, 25) { if (trie[1][i]) { if (! label[trie[1][i]]) a.a[1][trie[1][i]]++; } else a.a[1][1]++; } b.n = b.m = tot + 1, b.a[b.n][b.m] = 1; fo(i, 1, tot) { if (label[i]) continue; b.a[i][tot + 1] = 1; fo(j, 0, 25) { int now = i; while (now > 1 && ! trie[now][j]) now = fail[now]; if (trie[now][j]) now = trie[now][j]; if (label[now]) continue; b.a[i][now]++; } } while (m) { if (m & 1) a = a * b; b = b * b, m >>= 1; } // printf("%llu ", ans); printf("%llu\n", ans - a.a[1][tot + 1]); } return 0; }