zoukankan      html  css  js  c++  java
  • Luogu P2463 [SDOI2008]Sandy的卡片

    题目链接 (Click) (Here)

    真的好麻烦啊。。事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦。。(最好是八分钟能无脑把(SA)码对的程度(QAQ)

    这个题最开始我想的是(RMQ)遍历每一个子区间,但是意识到复杂度是(O(N^2))然后就(GG)了。怎么说呢,后缀数组和二分似乎是很常见的组合(和莫队也是?),这个题只需要在(height)数组里二分(lcp)长度即可,(check)函数里面处理一下,要让区间内所有原串都有至少一个子串。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 200010;
    
    int s[N], id[N];
    int n, m, num, len, tot = 10000;
    int sa[N], tp[N], rk[N], _rk[N], bin[N], height[N];
    
    void get_height (int n) {
    	int k = 0;
    	for (int i = 1; i <= n; ++i) {
    		if (k != 0) k--;
    		int j = sa[rk[i] - 1];
    		while (s[i + k] == s[j + k]) k++;
    		height[rk[i]] = k;
    	}
    }
    
    void base_sort (int n, int m) {
    	for (int i = 0; i <= m; ++i) bin[i] = 0;
    	for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
    	for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
    	for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
    }
    
    void suffix_sort (int n, int m) {
    	for (int i = 1; i <= n; ++i) {
    		rk[i] = s[i];
    		tp[i] = i;
    	}
    	base_sort (n, m);
    	for (int w = 1; w <= n; w <<= 1) {
    		int cnt = 0;
    		for (int i = n - w + 1; i <= n; ++i) {
    			tp[++cnt] = i;
    		}
    		for (int i = 1; i <= n; ++i) {
    			if (sa[i] > w) {
    				tp[++cnt] = sa[i] - w;
    			}
    		}
    		base_sort (n, m);
    		memcpy (_rk, rk, sizeof (rk));
    		rk[sa[1]] = cnt = 1;
    		for (int i = 2; i <= n; ++i) {
    			rk[sa[i]] = _rk[sa[i]] == _rk[sa[i - 1]] && _rk[sa[i] + w] == _rk[sa[i - 1] + w] ? cnt : ++cnt;
    		}
    		if (cnt == n) break;
    		m = cnt;
    	}
    }
    
    bool vis[1010]; int sta[N], top = 0;
    
    bool can_use (int l) {
    	while (top) vis[sta[top--]] = false;
    	for (int i = 1; i <= len; ++i) {
    		if (height[i] < l) {
    			while (top) vis[sta[top--]] = false;
    		}
    		if (!vis[id[sa[i]]]) {
    			vis[id[sa[i]]] = true;
    			sta[++top] = id[sa[i]];
    			if (top == n) return true;
    		}
    	}
    	return false;
    }
    
    int main () {
    	cin >> n;
    	int ban = 2000;
    	for (int i = 1; i <= n; ++i) {
    		cin >> m;
    		for (int j = 1; j <= m; ++j) {
    			cin >> s[++len]; //把所有的字符串整合到一个里
    			id[len] = i; // 表明主权(len号后缀(的lcp)属于串i)
    		}
    		s[++len] = ++ban; //隔开
    	}
    	for (int i = len; i >= 1; --i) {
    		s[i] = s[i] - s[i - 1] + 4000;
    	}
    	suffix_sort (len, 10000);
    	get_height (len);
    	int l = 0, r = len;
    	while (l < r) {
    		int mid = (l + r + 1) >> 1;
    		if (can_use (mid)) {
    			l = mid;
    		} else {
    			r = mid - 1;
    		}
    	}
    	cout << l + 1 << endl;
    }
    
    
  • 相关阅读:
    165. Compare Version Numbers
    164. Maximum Gap
    3、桶排序
    162. Find Peak Element
    160. Intersection of Two Linked Lists
    155. Min Stack
    154. Find Minimum in Rotated Sorted Array II
    153. Find Minimum in Rotated Sorted Array
    Linux/Unix系统编程手册 第二章:基本概念
    Linux/Unix系统编程手册 第一章:历史和标准
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10438209.html
Copyright © 2011-2022 走看看