【CCPC】CCPC 2023 Shenzhen Site G

Gene

#二分 #哈希 #字符串

题目描述

Let s s s and t t t be two strings with equal lengths M M M . Define f ( s , t ) = ∑ i = 1 M [ s i ≠ t i ] f (s, t) =\sum_{i=1}^M[s_i\neq t_i] f(s,t)=i=1M[si=ti]
You are given N N N strings s 1 , s 2 , ⋅ ⋅ ⋅ , s N s_1, s_2, · · · , s_N s1,s2,⋅⋅⋅,sN and a constant threshold K K K. Each of the string contains exactly M M M lowercase letters. You need to perform the following queries Q Q Q times:

• • Given a string t t t of length M M M , calculate ∑ i = 1 N [ f ( s i , t ) ≤ K ] \sum_{i=1}^N[f (s_i, t)\leq K] i=1N[f(si,t)K]

输入格式

The first line of the input contains four integers N N N, Q Q Q, M M M, and K K K ( 1 ≤ N , Q ≤ 300 , 1 ≤ M ≤ 60 , 000 , 1 ≤ K ≤ 10 ) . 1 ≤ N, Q ≤ 300, 1 ≤ M ≤ 60, 000,1 ≤ K ≤ 10). 1N,Q300,1M60,000,1K10).
The i − i- ith line of the next N N N lines contains a single string si consisting exactly M M M lowercase letters.
The i − i- ith line of the next Q Q Q lines contains a single string t t t consisting exactly M M M lowercase letters, indicating a query.

输出格式

For each query, output a single line contains a single integer, indicating the answer

样例 #1

样例输入 #1

6 4 4 1
kaki
kika
manu
nana
tepu
tero
kaka
mana
teri
anan

样例输出 #1

2
2
1
0

解法

解题思路

观察到 k ≤ 10 k\leq 10 k10,因此我们可以对字符串进行哈希,枚举 n n n个匹配串,然后每次二分出第 i ( i ≤ k ) i(i\leq k) i(ik)个不同的位置,如果能二分到最后的位置,那么这个匹配串就为合法的串了。

为了减少哈希碰撞,这里我们的哈希使用的是随机模数的哈希。

这样整体的时间复杂度在 O ( m q + n k l o g 2 m ) O(mq+nklog_2m) O(mq+nklog2m)

代码


mt19937_64 rng((unsigned int)chrono::steady_clock::now().time_since_epoch().count());

struct hash61 {
	hash61() {}

	static const uint64_t md = (1LL << 61) - 1;
	static uint64_t step;
	static vector<uint64_t> pw;

	uint64_t addmod(uint64_t a, uint64_t b) const {
		a += b;
		if (a >= md) a -= md;
		return a;
	}

	uint64_t submod(uint64_t a, uint64_t b) const {
		a += md - b;
		if (a >= md) a -= md;
		return a;
	}

	uint64_t mulmod(uint64_t a, uint64_t b) const {
		uint64_t l1 = (uint32_t)a, h1 = a >> 32, l2 = (uint32_t)b, h2 = b >> 32;
		uint64_t l = l1 * l2, m = l1 * h2 + l2 * h1, h = h1 * h2;
		uint64_t ret = (l & md) + (l >> 61) + (h << 3) + (m >> 29) + (m << 35 >> 3) + 1;
		ret = (ret & md) + (ret >> 61);
		ret = (ret & md) + (ret >> 61);
		return ret - 1;
	}

	void ensure_pw(int sz) {
		int cur = (int)pw.size();
		if (cur < sz) {
			pw.resize(sz);
			for (int i = cur; i < sz; i++) {
				pw[i] = mulmod(pw[i - 1], step);
			}
		}
	}

	vector<uint64_t> pref;
	int n;

	template<typename T>
	hash61(const T& s) {
		n = (int)s.size();
		ensure_pw(n + 1);
		pref.resize(n + 1);
		pref[0] = 1;
		for (int i = 0; i < n; i++) {
			pref[i + 1] = addmod(mulmod(pref[i], step), s[i]);
		}
	}

	inline uint64_t operator()(const int from, const int to) const {
		assert(0 <= from && from <= to && to <= n - 1);
		return submod(pref[to + 1], mulmod(pref[from], pw[to - from + 1]));
	}
};
uint64_t hash61::step = (md >> 2) + rng() % (md >> 1);
vector<uint64_t> hash61::pw = vector<uint64_t>(1, 1);

void solve() {
	int n, q, m, k;
	std::cin >> n >> q >> m >> k;

	std::vector<hash61>a(n + 1);
	for (int i = 1; i <= n; ++i) {
		std::string s;
		cin >> s; s = " " + s;
		a[i] = hash61(s);
	}

	while (q--) {
		std::string s;
		std::cin >> s;
		s = " " + s;
		
		auto b = hash61(s);

		int res = 0;
		for (int i = 1; i <= n; ++i) {
			int L = 1, R = m;
			for (int j = 1; j <= k; ++j) {
				int l = L, r = R, ans = -1;
				while (l <= r) {
					int mid = l + r >> 1;
					if (b(l, mid) == a[i](l, mid)) {
						ans = mid;
						l = mid + 1;
					}
					else {
						r = mid - 1;
					}
				}

				if (ans == -1) L++;
				else L = ans + 2;
			}

			if (L > m) ++res;
			else {
				if (b(L, m) == a[i](L, m)) ++res;
			}
		}

		std::cout << res << "\n";
	}

}
signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);

	int t = 1;
	//std::cin >> t;

	while (t--) {
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值