UVA1401 Remember the Word 题解

考虑一个动态规划,fif_i 表示前 ii 个字符的划分方案。枚举 ii,对于 ssii 个字符的某个后缀,如果出现在字典里,就转移。形式化地,如果 s[ji]s[j \cdots i] 为一个在字典的后缀,那么 fi=jfj1f_i = \sum \limits_{j} f_{j-1}f0=1f_0=1

但直接转移是 O(nm)O(nm) 的。发现字典每个字符串长度不超过过 100100,只需要枚举位数,用哈希判断即可。不过有点卡常。

#pragma GCC optimize("-Ofast,fast-math,-inline")
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <unordered_set>
using namespace std;
using ull = unsigned long long;

const int N = 3e5 + 5, M = 4005, K = 105, MOD = 20071027;

long long f[N];
string s;
int n;
string t[M];

ull hashing[N], hash2[M][K];

ull powe[N];
unordered_set<ull> st;

int main()
{
	ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
	int c = 0;
	powe[0] = 1;
	for (int i = 1; i < N; i++)
	{
		powe[i] = powe[i - 1] * 841;
	}
	while (cin >> s)
	{
		st.clear();
		int p = s.size();
		for (int i = 1; i <= p; i++)
		{
			hashing[i] = hashing[i - 1] * 841 + s[i - 1];
		}
		cin >> n;
		for (int i = 1; i <= n; i++)
		{
			cin >> t[i];
			int pp = t[i].size();
			for (int j = 1; j <= pp; j++)
			{
				hash2[i][j] = hash2[i][j - 1] * 841 + t[i][j - 1];
			}
			st.insert(hash2[i][pp]);
		}
		f[0] = 1LL;
		for (int i = 1; i <= p; i++)
		{
			f[i] = 0LL;
			int maxn = min(i, 100);
			for (int j = 1; j <= maxn; j++)
			{
				int l = i - j + 1, r = i;
				ull subhash = hashing[r] - hashing[l - 1] * powe[r - l + 1];
				if (st.count(subhash)) f[i] = (f[i] + f[l - 1]) % MOD;
			}
		}
		cout << "Case " << ++c << ": " << f[p] << "\n";
	}
	return 0;
}
posted @ 2023-07-24 21:24  HappyBobb  阅读(11)  评论(0)    收藏  举报  来源