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

    gate

    求第(k)小子串。
    可以用后缀自动机求解。

    (t=0),不同位置的相同子串算作一个。设(cnt[i])表示(i)(endpos)集合大小,即结束位置为(i)的子串个数。因为相同子串只算一次,所以直接设所有点的(cnt=1)即可。
    (t=1),不同位置的相同字串算作多个。这时正常维护(cnt[i] = cnt[i]+sum cnt[j](i=fa[j]))即可。
    (f[i])表示经过(i)的子串数量。
    (f[i] = cnt[i] + sum f[j](i=fa[j]))
    按拓扑序从后往前更新一遍(parent)树。

    找第(k)小子串:
    从根节点开始遍历。设(x)表示下一个字符,枚举(a-z)
    (k>f[ch[x]]),则说明要找的子串不在(ch[x])的子树上,(k)减去该子树大小,(k-f[ch[x]])
    否则,说明在(ch[x])的子树上,输出字符(x),走到节点(ch[x])(k)减去这个节点自身的大小,(k-cnt[ch[x]])
    直到(kle 0)时,说明当前子串已经找到,退出。

    注意:

    • 最后可能会有(k<0),因为一个节点上可能有多个子串。
    • 复制节点时,不要忘记设置新节点的(cnt=0)

    (code)

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    using namespace std;
    
    const int maxn = 5e5+10;
    
    int t,k,b[maxn<<1],rk[maxn<<1],f[maxn<<1];
    char s[maxn];
    
    struct SuffixAutomaton {
    	struct node {
    		int ch[26],fa,len,cnt;
    		void clean() {
    			memset(ch,0,sizeof(ch));
    			fa = len = cnt = 0;
    		}
    	} S[maxn<<1];
    	int root,last,siz;
    
    	void init() {
    		for(int i = 1; i <= siz; i++)
    			S[i].clean();
    		root = last = siz = 1;
    	}
    
    	void insert(int c) {
    		int p = last, now = ++siz;
    		S[now].cnt = 1;
    		S[now].len = S[p].len+1;
    		for(; p && !S[p].ch[c]; p = S[p].fa)
    			S[p].ch[c] = now;
    		if(!p) S[now].fa = root;
    		else {
    			int q = S[p].ch[c];
    			if(S[q].len == S[p].len+1)
    				S[now].fa = q;
    			else {
    				int q_new = ++siz;
    				S[q_new] = S[q];
    				S[q_new].cnt = 0;
    				S[q_new].len = S[p].len+1;
    				S[now].fa = S[q].fa = q_new;
    				for(; p && S[p].ch[c] == q; p = S[p].fa)
    					S[p].ch[c] = q_new;
    			}
    		}
    		last = now;
    	}
    
    	void calc() {
    		for(int i = 1; i <= siz; i++)
    			b[S[i].len]++;
    		for(int i = 1; i <= siz; i++)
    			b[i] += b[i-1];
    		for(int i = 1; i <= siz; i++)
    			rk[b[S[i].len]--] = i;
    		for(int i = siz; i; i--)
    			if(t) S[S[rk[i]].fa].cnt += S[rk[i]].cnt;
    			else S[rk[i]].cnt = 1;
    		S[root].cnt = 0;
    		for(int i = siz; i; i--) {
    			f[rk[i]] = S[rk[i]].cnt;
    			for(int j = 0; j < 26; j++)
    				f[rk[i]] += f[S[rk[i]].ch[j]];
    		}
    	}
    
    	void solve() {
    		if(k > f[root]) {
    			printf("-1");
    			return;
    		}
    		int now = root;
    		while(k > 0) {
    			for(int i = 0; i < 26; i++) {
    				if(!S[now].ch[i]) continue;
    				if(k > f[S[now].ch[i]])
    					k -= f[S[now].ch[i]];
    				else {
    					now = S[now].ch[i];
    					k -= S[now].cnt;
    					printf("%c",i+'a');
    					break;
    				}
    			}
    		}
    	}
    
    } SAM;
    
    int main() {
    	scanf("%s",s+1);
    	scanf("%d%d",&t,&k);
    	int n = strlen(s+1);
    	SAM.init();
    	for(int i = 1; i <= n; i++)
    		SAM.insert(s[i]-'a');
    	SAM.calc();
    	SAM.solve();
    	return 0;
    }
    
  • 相关阅读:
    《家庭财务总管》升级了(1.0.0.1)
    谁拥有接口?
    VScode调试C++工程
    NVIDIA显卡原生管理查询功能nvidiasmi的部分使用功能
    python版本的两款NVIDIA显卡管理查询工具
    pytorch之网络参数统计 torchstat & torchsummary
    电脑、笔记本、手机维修经验分享网站,专业领域网站
    Python使用pynvml查看GPU信息
    【转载】 Ubuntu下使用VSCode的launch.json及tasks.json编写
    笔记本挑电源适配器吗,是不是电压相同情况下保证功率大于等于原装适配器就可以保证笔记本正常运行???
  • 原文地址:https://www.cnblogs.com/mogeko/p/13323402.html
Copyright © 2011-2022 走看看