• 【BZOJ 4556】字符串


    【链接】h在这里写链接


    【题意】


        给你一个长度为n(n<=10^5)的字符串以及一个整数m(m<=10^5),代表询问的次数。
        每个询问由4个整数a,b,c,d给出
        表示询问s[a..b]的所有子串中和s[c..d]的最长公共前缀的长度


    【题解】


        暴力的写法?
        先求出原串的后缀数组;
        然后对于每一个询问.
        二分最长公共前缀mid,先找到Height[Rank[c]];
            然后往前往后找大于等于mid的Height;
                然后看看对于的Sa在不在[a,b]里面,以及Sa+mid-1<=b是不是成立
                以及c + mid - 1 <= d是否成立->这一点可以将二分的右界设置为d-c+1;
                找到一个就返回True即可。
                显然前缀越长越不可能,单调性比较显然

        复杂度?
        m*(log2n*常数)的样子?
        感觉能卡过去


    【错的次数】


    0

    【反思】


    在这了写反思

    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5;
    const int MAX_CHAR = 255;//每个数字的最大值。
    char s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存
    int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10];
    int Height[N + 10], Rank[N + 10];
    
    void build_Sa(int n, int m) {
    	int i, *x = T1, *y = T2;
    	for (i = 0; i<m; i++) C[i] = 0;
    	for (i = 0; i<n; i++) C[x[i] = s[i]]++;
    	for (i = 1; i<m; i++) C[i] += C[i - 1];
    	for (i = n - 1; i >= 0; i--) Sa[--C[x[i]]] = i;
    	for (int k = 1; k <= n; k <<= 1)
    	{
    		int p = 0;
    		for (i = n - k; i<n; i++) y[p++] = i;
    		for (i = 0; i<n; i++) if (Sa[i] >= k) y[p++] = Sa[i] - k;
    		for (i = 0; i<m; i++) C[i] = 0;
    		for (i = 0; i<n; i++) C[x[y[i]]]++;
    		for (i = 1; i<m; i++) C[i] += C[i - 1];
    		for (i = n - 1; i >= 0; i--) Sa[--C[x[y[i]]]] = y[i];
    		swap(x, y);
    		p = 1; x[Sa[0]] = 0;
    		for (i = 1; i<n; i++)
    			x[Sa[i]] = y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + k] == y[Sa[i] + k] ? p - 1 : p++;
    		if (p >= n) break;
    		m = p;
    	}
    }
    
    void getHeight(int n)
    {
    	int i, j, k = 0;
    	for (i = 1; i <= n; i++) Rank[Sa[i]] = i;
    	for (i = 0; i<n; i++) {
    		if (k) k--;
    		j = Sa[Rank[i] - 1];
    		while (s[i + k] == s[j + k]) k++;
    		Height[Rank[i]] = k;
    	}
    }
    
    int a, b, c, d;
    int n,m;
    
    bool check(int pos,int len)
    {
    	return (pos >= a && pos <= b) && (pos + len-1 <= b);
    }
    
    bool ok(int pos,int len)
    {
    	int temp = pos;
    	if (temp + 1 <= n && Height[temp+1] >= len && check(Sa[temp],len)) return true;
    	while (temp + 1 <= n && Height[temp + 1] >= len) 
    	{
    		if (check(Sa[temp + 1], len))
    			return true;
    		temp++;
    	}
    	if (pos - 1 >= 1 && Height[pos] >= len && check(Sa[pos],len)) return true;
    	while (pos - 1 >= 1 && Height[pos] >= len) 
    	{
    		if (check(Sa[pos - 1], len)) return true;
    		pos--;
    	}
    	return false;
    }
    
    
    int main() {
    	//freopen("F:\rush.txt", "r", stdin);
    	scanf("%d%d", &n, &m);
    	scanf("%s", s);
    	s[n] = 0;
    	build_Sa(n + 1, MAX_CHAR);//注意调用n+1
    	getHeight(n);
    	for (int i = 1; i <= m; i++)
    	{
    
    		scanf("%d%d%d%d", &a, &b, &c, &d);
    		a--, b--, c--, d--;
    		int l = 1, r = d - c + 1,temp = 0;//默认lcp为0
    		while (l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if (ok(Rank[c],mid))
    			{
    				temp = mid;
    				l = mid + 1;
    			}
    			else
    			{
    				r = mid - 1;
    			}
    		}
    		printf("%d
    ", temp);
    	}
    	return 0;
    }


  • 相关阅读:
    设计模式>经典设计模式一览 小强斋
    java基础>Java Collections Framework 小强斋
    如何查看python中包的版本
    gcc安装包下载地址
    Linux下boost库的编译及安装
    centos中如何自动获取IP、获取网关
    src/delly.h:8:10: fatal error: boost/graph/adjacency_list.hpp: No such file or directory
    linux系统中如何查看本机IP
    分布式事务解决方案
    Java常用的并发类总结列表
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7625982.html
Copyright © 2020-2023  润新知