• bzoj4556 [Tjoi2016&Heoi2016]字符串


    Description

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为 (n) 的字符串 (s) ,和 (m) 个问题。佳媛姐姐必须正确回答这 (m) 个问题,才能打开箱子拿到礼物,升职加薪,出任 (mathrm{CEO}) ,嫁给高富帅,走上人生巅峰。每个问题均有 (a,b,c,d) 四个参数,问你子串 (s[acdots b]) 的所有子串和 (s[ccdots d]) 的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

    Input

    输入的第一行有两个正整数 (n,m) ,分别表示字符串的长度和询问的个数。接下来一行是一个长为 (n) 的字符串。接下来 (m) 行,每行有 (4) 个数 (a,b,c,d) ,表示询问 (s[acdots b]) 的所有子串和 (s[ccdots d]) 的最长公共前缀的最大值。 (1le n,mle 100,000) ,字符串中仅有小写英文字母, (ale b,cle d,1le a,b,c,dle n)

    Output

    对于每一次询问,输出答案。

    Sample

    Sample Input

    5 5
    aaaaa
    1 1 1 5
    1 5 1 1
    2 3 2 3
    2 4 2 3
    2 3 2 4
    

    Sample Output

    1
    1
    2
    2
    2
    

    Solution

    用了一个鬼畜方法。

    首先把 (sa)(height) 给构造出来。然后就暴力扫 (lcp) ,遇到不符合长度限制的处理一下就好了。

    最坏是 (n^2) 的,但是 (mathrm{bzoj}) 的数据太弱了。

    还有就是通过此题我发现我的后缀数组板子是错的(无良 (mathrm{liurujia}) )!

    #include<bits/stdc++.h>
    using namespace std;
    
    #define N 100001
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define drp(i, a, b) for (int i = a; i >= b; i--)
    #define INF 0x7fffffff
    
    inline int read() {
    	int x = 0; char ch = getchar(); while (!isdigit(ch))  ch = getchar();
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x;
    }
    
    int sa[N], t1[N], t2[N], c[N], n, m, height[N], rnk[N];
    char s[N];
    
    void getSA(int n, int m) {
    	int *x = t1, *y = t2;
    	rep(i, 0, m - 1) c[i] = 0;
    	rep(i, 0, n - 1) c[x[i] = s[i]]++;
    	rep(i, 1, m - 1) c[i] += c[i - 1];
    	drp(i, n - 1, 0) sa[--c[x[i]]] = i;
    	for (int k = 1; k <= n; k <<= 1) {
    		int p = 0;
    		rep(i, n - k, n - 1) y[p++] = i;
    		rep(i, 0, n - 1) if (sa[i] >= k) y[p++] = sa[i] - k;
    		rep(i, 0, m - 1) c[i] = 0;
    		rep(i, 0, n - 1) c[x[y[i]]]++;
    		rep(i, 1, m - 1) c[i] += c[i - 1];
    		drp(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
    		swap(x, y);
    		p = 1, x[sa[0]] = 0;
    		rep(i, 1, n - 1) 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 j, k = 0;
    	rep(i, 1, n) rnk[sa[i]] = i;
    	for (int i = 0; i < n; height[rnk[i++]] = k)
    		for (k ? k-- : 0, j = sa[rnk[i] - 1]; s[i + k] == s[j + k]; k++);
    }
    
    int main() {
    	scanf("%d%d%s", &n, &m, s); s[n + 1] = 0;
    	getSA(n + 1, 'z' + 1), getHeight(n);
    	while (m--) {
    		int a = read() - 1, b = read() - 1, c = read() - 1, d = read() - 1;
    		int S = rnk[c], ans = 0, mn = INF;
    		if (sa[S] >= a && sa[S] <= b) ans = max(ans, min(d - c + 1, b - sa[S] + 1));
    		drp(i, S, 2) {
    			if (height[i] <= ans) break;
    			mn = min(mn, height[i]);
    			if (sa[i - 1] >= a && sa[i - 1] <= b) ans = max(ans, min(min(mn, b - sa[i - 1] + 1), d - c + 1));
    		}
    		mn = INF;
    		rep(i, S + 1, n) {
    			if (height[i] <= ans) break;
    			mn = min(mn, height[i]);
    			if (sa[i] >= a && sa[i] <= b) ans = max(ans, min(min(mn, b - sa[i] + 1), d - c + 1));
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    进程与线程的区别iOS
    java面试题(中)
    java面试题(上)
    [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
    [Asp.net 5] DependencyInjection项目代码分析3-Ninject
    [Asp.net 5] DependencyInjection项目代码分析2-Autofac
    [Asp.net 5] DependencyInjection项目代码分析
    leetcode25 K个一组翻转链表
    leetcode128 最长连续序列
    leetcode124 二叉树中的最大路径和
  • 原文地址:https://www.cnblogs.com/aziint/p/8630499.html
Copyright © 2020-2023  润新知