• 【hdu 2328】Corporate Identity


    【链接】h在这里写链接


    【题意】


    找一个字典序最小的公共最长子串;

    【题解】


    后缀数组。
    把所有的串用不同的分隔符分开。(大于'z'的分隔符);
    然后求出那几个固定的数组。
    二分一下那个子串的长度.
    看看是不是在N个串里面都有这个串即可。
    可以用一个下标,来记录某个位置开始的后缀是第几个串里面的(即输入的N个串里面的哪一个串).
    子串长度越大显然越不可能存在。
    (因子本来就是按照后缀排的。所以找到的第一个符合要求的子串肯定是字典序最小的)

    【错的次数】


    0

    【反思】


    一开始记录答案的时候,记录错了,应该记录的是Sa[i]而不是i...
    因为i是排名啊。。Sa[i]才是这个排名的后缀的起点。

    【代码】

    /*
    N*logn复杂求出Rank数组以及Sa数组
    Rank数组下标是从0开始的,表示的是从i开始的后缀的排名(排名>=1).
    Sa数组又是从1开始的,表示的是第i名的(i>=1)后缀是从字符串中的第几个字符开始的(字符位置>=0).
    Height[i]从1开始,表示的是字典序为i和字典序为i-1的后缀的最长公共前缀。
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 8e5 + 6000;
    const int SN = 2e2;
    const int MAX_CHAR = 4500;//每个数字的最大值。
    int s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存
    int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10], T;
    int Height[N + 10], Rank[N + 10], idx[N + 10], in[N + 10], tag;
    char str[SN + 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;
    	}
    }
    
    void check(int pos, int i, int &num) {
    	if (in[idx[Sa[pos]]] != i) {
    		num++;
    		in[idx[Sa[pos]]] = i;
    	}
    }
    
    bool ok(int len, int n) {
    	for (int i = 1; i <= T; i++) in[i] = 0;
    	for (int i = 2; i <= n; i++)
    		if (Height[i] >= len) {
    			int j = i, num = 1;
    			in[idx[Sa[i - 1]]] = i;
    			check(i, i, num);
    			while (j + 1 <= n && Height[j + 1] >= len) {
    				j++;
    				check(j, i, num);
    			}
    			if (num == T) {
    				tag = Sa[i - 1];
    				return true;
    			}
    			i = j;
    		}
    	return false;
    }
    
    int main() {
    	//freopen("F:\\rush.txt", "r", stdin);
    	ios::sync_with_stdio(0), cin.tie(0);
    	while (cin >> T && T) {
    		int n = 0;
    		for (int i = 1; i <= T; i++) {
    			cin >> str;
    			for (int j = 0; j < (int)strlen(str); j++) {
    				idx[n] = i;
    				s[n++] = str[j];
    			}
    			s[n++] = 300 + i;
    		}
    		s[n] = 0;
    		build_Sa(n + 1, MAX_CHAR);//注意调用n+1
    		getHeight(n);
    		int l = 1, r = 200, temp = 0;
    		while (l <= r) {
    			int m = (l + r) >> 1;
    			if (ok(m, n)) {
    				temp = m;
    				l = m + 1;
    			}
    			else
    				r = m - 1;
    		}
    		if (temp == 0) {
    			cout << "IDENTITY LOST" << endl;
    		}
    		else {
    			for (int i = tag; i <= tag + temp - 1; i++)
    				cout << char(s[i]);
    			cout << endl;
    		}
    	}
    	return 0;
    }


  • 相关阅读:
    ThinkPhp3.2.3缓存漏洞复现以及修复建议
    thinkphp3.2.3 缓存导致getshell终极解决办法
    phpstudy后门漏洞复现php5.2
    phpStudy后门漏洞利用复现
    SQL语句利用日志写shell拿权限
    针对phpstudy默认设置的利用
    黑暗世界的搜索引擎
    CVE-2019-0708—微软RDP远程桌面代码执行漏洞复现
    记一次渗透某XX站
    通过USB 2.0电缆手动设置内核模式调试
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626013.html
Copyright © 2020-2023  润新知