zoukankan      html  css  js  c++  java
  • P3975 [TJOI2015]弦论 SAM+right数组

    题意:

    戳这里

    分析:

    (sam) 裸题,求第 (k) 大字符串

    首先建出 (sam) 然后求出 (siz[i]) 表示 (i) 节点代表的串的 (endpos) 的集合大小

    然后分情况讨论:

    1. (T==0) 只统计本质不同的串的个数,所以所有点的 (siz[i]) 都置为 1
    2. (T==1) (siz[i]) 不变

    按照长度进行拓扑排序,因为 (sam) 上的点的 (parent) 树的 (BFS) 序等价于将 (len) 值类似于 (sa) 的基数排序后得到的序列一样(博主太笨,不会证明)

    然后按照拓扑序,将儿子的 (siz) 值累加到父亲节点上,就得到经过每个点(即每种子串的出现次数),然后 (DFS) 得到第 (k) 个就可以了

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 5e5+5;
    	int len[maxn<<1],siz[maxn<<1],sum[maxn<<1],trans[maxn<<1][27],link[maxn<<1];
    	int t[maxn<<1],sa[maxn<<1]; 
    	int n,T,k,cnt=1,lst=1;
    	char ch[maxn];
    	
    	void insert(int x)
    	{
    		int cur=++cnt;
    		int tmp=lst;lst=cur;
    		len[cur]=len[tmp]+1;siz[cur]=1;
    		for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
    		if(!tmp) link[cur]=1;
    		else
    		{
    			int q=trans[tmp][x];
    			if(len[tmp]+1==len[q]) link[cur]=q;
    			else
    			{
    				int clone=++cnt;
    				len[clone]=len[q];link[clone]=link[q];
    				memcpy(trans[clone],trans[q],sizeof(trans[q]));
    				link[cur]=link[q]=clone;
    				len[clone]=len[tmp]+1;
    				for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
    			}
    		}
    		
    	}
    	
    	void solve(int u,int k)
    	{
    		if(k<=siz[u]) return ;
    		k-=siz[u];
    		for(int i=0;i<26;i++)
    		{
    			if(!trans[u][i]) continue;
    			if(k>sum[trans[u][i]]) k-=sum[trans[u][i]];
    			else
    			{
    				putchar(i+'a');
    				solve(trans[u][i],k);
    				return;
    			}	
    		}
    	}
    	
    	void work()
    	{
    		scanf("%s",ch+1);n=strlen(ch+1);scanf("%d%d",&T,&k);
    		for(int i=1;i<=n;i++) insert(ch[i]-'a');
    		for(int i=1;i<=cnt;i++) t[len[i]]++;
    		for(int i=1;i<=cnt;i++) t[i]+=t[i-1];
    		for(int i=1;i<=cnt;i++) sa[t[len[i]]--]=i;
    		for(int i=cnt;i>=1;i--) siz[link[sa[i]]]+=siz[sa[i]];
    		for(int i=1;i<=cnt;i++) T==0?(sum[i]=siz[i]=1):(sum[i]=siz[i]);
    		siz[1]=sum[1]=0;
    		for(int i=cnt;i>=1;i--)
    		{
    			sum[sa[i]]=siz[sa[i]];
    			for(int j=0;j<26;j++)
    			{
    				if(trans[sa[i]][j]) sum[sa[i]]+=sum[trans[sa[i]][j]];
    			}
    		}
    		if(sum[1]<k) printf("-1
    ");
    		else solve(1,k);
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    } 
    
  • 相关阅读:
    [c++ 11x rvalue reference]
    Exception Cost
    How to set NoStepInto for VS debugging
    STL算法find_if和find
    [转载]The Biggest Changes in C++11 (and Why You Should Care)
    QT信号和槽
    读《构建之法》前三章有感
    复利计算器(3)——数据库
    《构建之法》——第四章
    操作系统命令行解释
  • 原文地址:https://www.cnblogs.com/youth518/p/14152595.html
Copyright © 2011-2022 走看看