[BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

题目链接:BZOJ - 3207

题目分析

先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x 。

这一步可以使用可持久化线段树来做,虽然感觉可以有更简单的做法,但是我没有什么想法...

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;

const int MaxN = 200000 + 5, P = 233, Mod = 3371723, MaxNode = 8000000 + 5; 

int n, m, k, en, TL_Index, Node_Index;
int A[MaxN], B[MaxN], Root[MaxN], Lc[MaxNode], Rc[MaxNode], T[MaxNode];

struct HashNode
{
	int Pos, TL;
	HashNode *Next;
} H[MaxN], *Ph = H, *Hash[Mod + 5];

bool Cmp(int *AA, int x, int *AB, int y) {
	for (int i = 0; i < k; ++i)
		if (AA[x + i] != AB[y + i]) return false;
	return true;
}

void Insert(int &Now, int Last, int s, int t, int x) {
	if (Now == 0) Now = ++Node_Index;
	if (s == t) {
		T[Now] = T[Last] + 1;
		return;
	}
	int m = (s + t) >> 1;
	if (x <= m) {
		Rc[Now] = Rc[Last];
		Insert(Lc[Now], Lc[Last], s, m, x);
	}
	else {
		Lc[Now] = Lc[Last];
		Insert(Rc[Now], Rc[Last], m + 1, t, x);
	}
}

int main()
{
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= n; ++i) scanf("%d", &A[i]);
	en = n - k + 1;
	int HN, TL_i;
	HashNode *Now;
	TL_Index = 0;
	Node_Index = 0;
	for (int i = 1; i <= en; ++i) {
		HN = 0;
		for (int j = i; j < i + k; ++j) {
			HN = HN * P + A[j];
			if (HN > Mod) HN %= Mod;
		}
		Now = Hash[HN];
		TL_i = 0;
		while (Now != NULL) {
			if (Cmp(A, i, A, Now -> Pos)) {
				TL_i = Now -> TL;
				break;
			}
			Now = Now -> Next;
		}
		if (TL_i == 0) {
			++Ph; Ph -> Pos = i;
			Ph -> TL = TL_i = ++TL_Index;
			Ph -> Next = Hash[HN]; Hash[HN] = Ph;
		}
		Insert(Root[i], Root[i - 1], 1, n, TL_i);
	}
	int l, r, s, t, mid, x, y;
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &l, &r);
		for (int j = 1; j <= k; ++j) scanf("%d", &B[j]);
		HN = 0;
		for (int j = 1; j <= k; ++j) {
			HN = HN * P + B[j];
			if (HN > Mod) HN %= Mod;
		}
		TL_i = 0;
		Now = Hash[HN];
		while (Now != NULL) {
			if (Cmp(B, 1, A, Now -> Pos)) {
				TL_i = Now -> TL;
				break;
			}
			Now = Now -> Next;
		}
		if (TL_i == 0 || r - l + 1 < k) printf("Yes\n");
		else {
			r = r - k + 1;
			x = Root[l - 1]; y = Root[r];
			s = 1; t = n;
			while (s != t) {
				mid = (s + t) >> 1;
				if (TL_i <= mid) {
					x = Lc[x]; y = Lc[y];
					t = mid;
				}
				else {
					x = Rc[x]; y = Rc[y];
					s = mid + 1;
				}
			}
			if (T[y] - T[x] > 0) printf("No\n");
			else printf("Yes\n");
		}
	}
	return 0;
}

  

时间: 2024-10-21 18:13:59

[BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】的相关文章

BZOJ 3207: 花神的嘲讽计划Ⅰ( hash + 可持久化线段树 )

O(NK)暴力搞出所有子串的哈希值, 然后就对哈希值离散化建权值线段树, 就是主席树的经典做法了.总时间复杂度O(NK+(N+Q)logN) -------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespa

【BZOJ3207】花神的嘲讽计划Ⅰ hash+可持久化线段树

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45688093"); } 题解: 首先因为嘲讽长度固定,所以我们可以给每个点固定一个hash值(不固定的话我还真不会做). 然后用可持久化线段树实现一段区间内有哪些数,然后查询一段区间是否有要的那个数就行了. 代码: #include

【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define uint unsigned int 4 #define ull unsigned long long 5 #define inf 4294967295 6 #define N 100005 7 #define M 100005 8 #

BZOJ 3207 花神的嘲讽计划I Hash+可持久化线段树

题目大意:给定一个数字串,多次求某个区间内有没有一个长度为k的子串 首先对字符串进行哈希 然后问题就转化成了求一个区间内有没有某个数 可持久化线段树即可 其实我觉得划分树会更快一些 可以写写 ※注意事项: 1.n<=200000 我找不到数据范围是眼科大夫去找老阎的关系? 2.哈希值用unsigned long long 铁则 unsigned int 会被卡掉 3.线段树那里直接x+y>>1会爆unsigned long long 转换一下 x+y>>1=(x>>

[BZOJ]3207花神的嘲讽计划Ⅰ

先把长度为k的字符串哈希掉,然后用可持久化线段树判断是否存在... 可持久化线段树直接上模板,然而哈希... 这里有三种哈希方法:①排个序,去个重,查找的时候二分 ②hash[i]=hash[i-1]*大质数+val[i] ③鬼畜查字符版哈希 下面的代码是第一种,然而加了读入优化更慢是什么鬼QAQ 1 #include<stdio.h> 2 #include<ctype.h> 3 #include<algorithm> 4 using namespace std; 5

bzoj 3207: 花神的嘲讽计划Ⅰ

Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: "哎你傻不傻的![hqz:大笨J]" "这道题又被J屎过了!!" "J这程序怎么跑这么快!J要逆袭了!" -- 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. "J你在讲什么!" "我在讲XXX!" "哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!"

【BZOJ3207】花神的嘲讽计划Ⅰ Hash+主席树

[BZOJ3207]花神的嘲讽计划Ⅰ Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就

【bzoj3207】花神的嘲讽计划Ⅰ Hash+STL-map+莫队算法

题目描述 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就讲这个了?哎你傻不傻的!” “……” DJ对这种情景

BZOJ_3207_花神的嘲讽计划Ⅰ_哈希+主席树

Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就讲这个了?哎你傻不傻的!” “……”