• [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
    ");
    		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
    ");
    			else printf("Yes
    ");
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    shiro什么时候会进入doGetAuthorizationInfo(PrincipalCollection principals)
    Kali2安装完成后的设置
    Springboot打包war
    2017总结及2018计划
    gitlab数据库
    Entity Framework学习
    从零开始编写操作系统——bochs
    Docker基本操作
    Jenkins打包安卓时提示没同意constraintLayout的license的解决方法
    env:bash 解决
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4251833.html
Copyright © 2020-2023  润新知