zoukankan      html  css  js  c++  java
  • [CTSC2012]熟悉的文章 (后缀自动机 单调队列)

    /*
    首先答案显然是具有单调性的, 所以可以二分进行判断
    
    然后当我们二分过后考虑dp来求最长匹配个数, 发现每个点能够转移的地点 肯定是一段区间, 然后这样就能够得到一个log^2算法
    至于每个点的匹配最长区间, 我们可以预处理出所有地点的最长匹配串
    
    然后发现这个东西可以进行单调栈优化, 原因是往后能往前最大匹配到的点是不会超过前面的, 否则前面那个也会更长
    
    然后就能快乐地一个log了
    
    
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #define ll long long
    #define M 2800010
    #define mmp make_pair
    using namespace std;
    int read() {
    	int nm = 0, f = 1;
    	char c = getchar();
    	for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    	return nm * f;
    }
    char s[M];
    int ch[M][2], cnt = 1, lst = 1, fa[M], len[M], n, m;
    
    void insert(int c) {
    	int p = ++cnt, f = lst;
    	lst = p;
    	len[p] = len[f] + 1;
    	while(f && !ch[f][c]) ch[f][c] = p, f = fa[f];
    	if(f == 0) {
    		fa[p] = 1;
    	} else {
    		int q = ch[f][c];
    		if(len[q] == len[f] + 1) {
    			fa[p] = q;
    		} else {
    			int nq = ++cnt;
    			memcpy(ch[nq], ch[q], sizeof(ch[q]));
    			fa[nq] = fa[q];
    			len[nq] = len[f] + 1;
    			fa[p] = fa[q] = nq;
    			while(f && ch[f][c] == q) ch[f][c] = nq, f = fa[f];
    		}
    	}
    }
    int q[M], h, t, pre[M], f[M];
    bool check(int k) {
    	int l = strlen(s + 1);
    	h = 1, t = 0;
    	for(int i = 1; i <= l; i++) {
    		f[i] = f[i - 1];
    		if(i < k) continue;
    		while(h <= t && f[q[t]] - q[t] <= f[i - k] - i + k) t--;
    		q[++t] = i - k;
    		while(h <= t && q[h] < i - pre[i]) h++;
    		if(h <= t) f[i] = max(f[i], f[q[h]] + i - q[h]);
    	}
    	return f[l] * 10 >= l * 9;
    }
    
    void getpre() {
    	int up = strlen(s + 1), now =  1, lenn = 0;
    	for(int i = 1; i <= up; i++) {
    		int c = s[i] - '0';
    
    		while(now && !ch[now][c]) now = fa[now], lenn = len[now];
    		if(!now) now = 1, lenn = 0;
    		else now = ch[now][c], lenn++;
    
    		pre[i] = lenn;
    	}
    }
    
    int work() {
    	getpre();
    	int l = 1, r = strlen(s + 1);
    	while(l + 1 < r) {
    		int mid = (l + r) >> 1;
    		if(check(mid)) l = mid;
    		else r = mid;
    	}
    	if(!check(l)) return -1;
    	if(check(r)) return r;
    	return l;
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= m; i++) {
    		lst = 1;
    		scanf("%s", s + 1);
    		int l = strlen(s + 1);
    		for(int j = 1; j <= l; j++) insert(s[j] - '0');
    	}
    	while(n--) {
    		scanf("%s", s + 1);
    		cout << work() << "
    ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    【转载】Unity的内存管理与性能优化
    [转载]有关placement new
    国内外有用的课程资源
    os模块批量重命名多个工作簿
    利用xlwings将一个工作表,拆成多个工作簿
    利用xlwings批量打开同一文件夹下的N多EXCEL表格
    回归初心,探索真我写在2022年的开始
    利用xlwings在多个工作簿中批量新增工作表
    今日份试题,关于Python办公自动化应用
    随想
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/10685328.html
Copyright © 2011-2022 走看看