• spoj New Distinct Substrings


    vjudge原地爆炸...

    题意:求一个字符串不同的子串的个数

    策略:后缀数组

    利用后缀数组的sa和height两个功能强大的数组,我们可以实现上述操作

    首先有个很显然的结论:一个字符串的所有子串=它后缀的所有前缀

    这是很显然的,因为一个后缀的前缀遍历了所有以该后缀起点为起点的字符串的子串,那么如果我们遍历所有后缀的,就能找出这个字符串的所有子串了

    所以对于一个起点为sa[i]的字符串,最多能提供的贡献就是l-sa[i]+1,而再考虑重复字符串的个数,也就是这个后缀所有的与其他后缀最长的公共前缀,这个后缀的贡献就是l-sa[i]+1-height[i]

    然后累计即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    int sa[50005];
    int rk[50005];
    int height[50005];
    int f1[50005];
    int f2[50005];
    int f3[50005];
    int has[50005];
    char s[50005];
    int l,m=127;
    void init()
    {
    	memset(sa,0,sizeof(sa));
    	memset(rk,0,sizeof(rk));
    	memset(has,0,sizeof(has));
    	memset(f1,0,sizeof(f1));
    	memset(f2,0,sizeof(f2));
    	memset(f3,0,sizeof(f3));
    	memset(height,0,sizeof(height));
    	m=127;
    }
    void turnit()
    {
    	memcpy(f3,f1,sizeof(f3));
    	memcpy(f1,f2,sizeof(f1));
    	memcpy(f2,f3,sizeof(f2));
    }
    void get_sa()
    {
    	for(int i=1;i<=l;i++)
    	{
    		f1[i]=s[i];
    		has[f1[i]]++;
    	}
    	for(int i=2;i<=m;i++)
    	{
    		has[i]+=has[i-1];
    	}
    	for(int i=l;i>=1;i--)
    	{
    		sa[has[f1[i]]--]=i;
    	}
    	for(int k=1;k<=l;k<<=1)
    	{
    		int tot=0;
    		for(int i=l-k+1;i<=l;i++)
    		{
    			f2[++tot]=i;
    		}
    		for(int i=1;i<=l;i++)
    		{
    			if(sa[i]>k)
    			{
    				f2[++tot]=sa[i]-k;
    			}
    		}
    		for(int i=1;i<=m;i++)
    		{
    			has[i]=0;
    		}
    		for(int i=1;i<=l;i++)
    		{
    			has[f1[i]]++;
    		}
    		for(int i=2;i<=m;i++)
    		{
    			has[i]+=has[i-1];			
    		}
    		for(int i=l;i>=1;i--)
    		{
    			sa[has[f1[f2[i]]]--]=f2[i];
    			f2[i]=0;
    		}
    		turnit();
    		f1[sa[1]]=1;
    		tot=1;
    		for(int i=2;i<=l;i++)
    		{
    			if(f2[sa[i]]==f2[sa[i-1]]&&f2[sa[i]+k]==f2[sa[i-1]+k])
    			{
    				f1[sa[i]]=tot;
    			}else
    			{
    				f1[sa[i]]=++tot;
    			}
    		}
    		if(tot==l)
    		{
    			break;
    		}
    		m=tot;
    	}
    	for(int i=1;i<=l;i++)
    	{
    		rk[sa[i]]=i;
    	}
    	int f=0;
    	for(int i=1;i<=l;i++)
    	{
    		if(rk[i]==1)
    		{
    			continue;
    		}
    		if(f)
    		{
    			f--;
    		}
    		int j=sa[rk[i]-1];
    		while(s[i+f]==s[j+f])
    		{
    			f++;
    		}
    		height[rk[i]]=f;
    	}
    }
    void solve()
    {
    	int ss=0;
    	for(int i=1;i<=l;i++)
    	{
    		ss-=l-sa[i]+1-height[i];
    	}
    	printf("%d
    ",ss);
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		init();
    		scanf("%s",s+1);
    		l=strlen(s+1);
    		get_sa();
    		solve();
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    SQL基础篇——如何搭建一个数据库
    SQL基础篇---基本概念解析
    联合体与结构体的区别
    结构体和它在链表中的使用
    火线零线地线
    第十二章 泛型
    Winform 控件使用集锦
    全局钩子和局部钩子
    第八章 方法
    第七章 常量和字段
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9708939.html
Copyright © 2020-2023  润新知