zoukankan      html  css  js  c++  java
  • Luogu P3975 [TJOI2015]弦论

    [题目链接 (Click) (Here)](P3975 [TJOI2015]弦论)

    题目大意:

    • 重复子串不算的第(k)大子串

    • 重复子串计入的第(k)大子串

    写法:后缀自动机。

    (OI) (Wiki)上介绍的写法不太一样,因为要同时解决两个问题。

    把字符串每个前缀所在等价类的(siz)记为(1),然后在(parent) (tree)上跑一次统计,就可以求出来每一个等价类在串中出现的次数。这里采用类似后缀排序的方法,对字符串按(len)为关键字进行排序。至于经过每个点的路径数(sum),可以在(Trie)边上对后面节点的(sum)(=每一个等价类在串中出现次数)求和得到(初始值等于(siz),因为每个点还有不选的情况)。

    不要忘了把(siz[1])(sum[1])清空!

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1100010;
    
    char s[N];
    int las = 1, node = 1;
    int fa[N], len[N], siz[N], ch[N][26];
    
    void extend (int c) {
    	register int p, q, x, y;
        p = las, q = ++node; las = q;
    	len[q] = len[p] + 1; siz[q] = 1;
    	while (p != 0 && ch[p][c] == 0) {
    		ch[p][c] = q;
    		p = fa[p];
    	}
    	if (p == 0) {
    		fa[q] = 1;
    	} else {
    	    x = ch[p][c];
    		if (len[x] == len[p] + 1) {
    			fa[q] = x;
    		} else {
    		    y = ++node;
    			fa[y] = fa[x];
    			fa[x] = fa[q] = y;
    			len[y] = len[p] + 1;
    			memcpy (ch[y], ch[x], sizeof (ch[x]));
    			while (p != 0 && ch[p][c] == x) {
    				ch[p][c] = y;
    				p = fa[p];
    			}
    		}
    	}
    }
    
    int t, k, nd[N], bin[N]; long long sum[N];
    
    void output (int u) {
    	if (k <= siz[u]) return;
    	k -= siz[u];
    	register int i;
    	for (i = 0; i < 26; ++i) {
    		if (ch[u][i]) {
    			if (k > sum[ch[u][i]]) {
    				k -= sum[ch[u][i]];
    			} else {
    				printf ("%c", i + 'a');
    				output (ch[u][i]);
    				return;
    			}
    		}
    	}
    }
    
    int main () {
    	scanf ("%s %d %d", s, &t, &k);
    	register int i, j, n;
        n = strlen (s);
    	for (i = 0; i < n; ++i) extend (s[i] - 'a');
    	for (i = 1; i <= node; ++i) bin[len[i]]++;
    	for (i = 1; i <= node; ++i) bin[i] += bin[i - 1];
    	for (i = 1; i <= node; ++i) nd[bin[len[i]]--] = i;
    	for (i = node; i >= 1; --i) siz[fa[nd[i]]] += siz[nd[i]];
    	for (i = 1; i <= node; ++i) t == 0 ? (sum[i] = siz[i] = 1) : (sum[i] = siz[i]);
    	siz[1] = sum[1] = 0;
    	for (i = node; i >= 1; --i) {
    		for (j = 0; j < 26; ++j) {
    			if (ch[nd[i]][j]) {
    				sum[nd[i]] += sum[ch[nd[i]][j]];
    			}
    		}
    	}
    	if (sum[1] < k) {
    		puts ("-1");
    	} else {
    		output (1);
    	}
    }
    
    

    (p.s)关于后缀数组求第一问的方法:

    枚举每一个后缀,第i个后缀对答案的贡献为(len−sa[i]+1−height[i])

  • 相关阅读:
    Python datetime time 等时间 日期 之间的计算和相互转化
    微信浏览器的html5页面显示配置等问题汇集 1,禁止微信浏览器分享页面链接 (定点更新)
    《Monitoring and Tuning the Linux Networking Stack: Receiving Data》翻译
    kubernetes安全认证相关资料
    ovn-architecture 摘要
    apt-get tips
    CNI插件编写框架分析
    ovn-kubernetes安装指南
    ovn-kubernetes执行流程概述
    《OVN Logical Flows and ovn-trace》翻译
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10452644.html
Copyright © 2011-2022 走看看